xref: /freebsd/sys/dev/mpi3mr/mpi3mr.c (revision 2d1d418e1e7bc8325bb052185c17c81a674d0c4e)
1*2d1d418eSSumit Saxena /*
2*2d1d418eSSumit Saxena  * SPDX-License-Identifier: BSD-2-Clause
3*2d1d418eSSumit Saxena  *
4*2d1d418eSSumit Saxena  * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved.
5*2d1d418eSSumit Saxena  * Support: <fbsd-storage-driver.pdl@broadcom.com>
6*2d1d418eSSumit Saxena  *
7*2d1d418eSSumit Saxena  * Authors: Sumit Saxena <sumit.saxena@broadcom.com>
8*2d1d418eSSumit Saxena  *	    Chandrakanth Patil <chandrakanth.patil@broadcom.com>
9*2d1d418eSSumit Saxena  *
10*2d1d418eSSumit Saxena  * Redistribution and use in source and binary forms, with or without
11*2d1d418eSSumit Saxena  * modification, are permitted provided that the following conditions are
12*2d1d418eSSumit Saxena  * met:
13*2d1d418eSSumit Saxena  *
14*2d1d418eSSumit Saxena  * 1. Redistributions of source code must retain the above copyright notice,
15*2d1d418eSSumit Saxena  *    this list of conditions and the following disclaimer.
16*2d1d418eSSumit Saxena  * 2. Redistributions in binary form must reproduce the above copyright notice,
17*2d1d418eSSumit Saxena  *    this list of conditions and the following disclaimer in the documentation and/or other
18*2d1d418eSSumit Saxena  *    materials provided with the distribution.
19*2d1d418eSSumit Saxena  * 3. Neither the name of the Broadcom Inc. nor the names of its contributors
20*2d1d418eSSumit Saxena  *    may be used to endorse or promote products derived from this software without
21*2d1d418eSSumit Saxena  *    specific prior written permission.
22*2d1d418eSSumit Saxena  *
23*2d1d418eSSumit Saxena  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24*2d1d418eSSumit Saxena  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25*2d1d418eSSumit Saxena  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26*2d1d418eSSumit Saxena  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27*2d1d418eSSumit Saxena  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28*2d1d418eSSumit Saxena  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29*2d1d418eSSumit Saxena  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30*2d1d418eSSumit Saxena  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31*2d1d418eSSumit Saxena  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32*2d1d418eSSumit Saxena  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33*2d1d418eSSumit Saxena  * POSSIBILITY OF SUCH DAMAGE.
34*2d1d418eSSumit Saxena  *
35*2d1d418eSSumit Saxena  * The views and conclusions contained in the software and documentation are
36*2d1d418eSSumit Saxena  * those of the authors and should not be interpreted as representing
37*2d1d418eSSumit Saxena  * official policies,either expressed or implied, of the FreeBSD Project.
38*2d1d418eSSumit Saxena  *
39*2d1d418eSSumit Saxena  * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131
40*2d1d418eSSumit Saxena  *
41*2d1d418eSSumit Saxena  * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD
42*2d1d418eSSumit Saxena  */
43*2d1d418eSSumit Saxena 
44*2d1d418eSSumit Saxena #include <sys/cdefs.h>
45*2d1d418eSSumit Saxena __FBSDID("$FreeBSD$");
46*2d1d418eSSumit Saxena 
47*2d1d418eSSumit Saxena #include <sys/types.h>
48*2d1d418eSSumit Saxena #include <sys/param.h>
49*2d1d418eSSumit Saxena #include <sys/systm.h>
50*2d1d418eSSumit Saxena #include <sys/kernel.h>
51*2d1d418eSSumit Saxena #include <sys/module.h>
52*2d1d418eSSumit Saxena #include <sys/bus.h>
53*2d1d418eSSumit Saxena #include <sys/conf.h>
54*2d1d418eSSumit Saxena #include <sys/malloc.h>
55*2d1d418eSSumit Saxena #include <sys/sysctl.h>
56*2d1d418eSSumit Saxena #include <sys/uio.h>
57*2d1d418eSSumit Saxena 
58*2d1d418eSSumit Saxena #include <machine/bus.h>
59*2d1d418eSSumit Saxena #include <machine/resource.h>
60*2d1d418eSSumit Saxena #include <sys/rman.h>
61*2d1d418eSSumit Saxena 
62*2d1d418eSSumit Saxena #include <dev/pci/pcireg.h>
63*2d1d418eSSumit Saxena #include <dev/pci/pcivar.h>
64*2d1d418eSSumit Saxena #include <dev/pci/pci_private.h>
65*2d1d418eSSumit Saxena 
66*2d1d418eSSumit Saxena #include <cam/cam.h>
67*2d1d418eSSumit Saxena #include <cam/cam_ccb.h>
68*2d1d418eSSumit Saxena #include <cam/cam_debug.h>
69*2d1d418eSSumit Saxena #include <cam/cam_sim.h>
70*2d1d418eSSumit Saxena #include <cam/cam_xpt_sim.h>
71*2d1d418eSSumit Saxena #include <cam/cam_xpt_periph.h>
72*2d1d418eSSumit Saxena #include <cam/cam_periph.h>
73*2d1d418eSSumit Saxena #include <cam/scsi/scsi_all.h>
74*2d1d418eSSumit Saxena #include <cam/scsi/scsi_message.h>
75*2d1d418eSSumit Saxena #include <cam/scsi/smp_all.h>
76*2d1d418eSSumit Saxena #include <sys/queue.h>
77*2d1d418eSSumit Saxena #include <sys/kthread.h>
78*2d1d418eSSumit Saxena #include "mpi3mr.h"
79*2d1d418eSSumit Saxena #include "mpi3mr_cam.h"
80*2d1d418eSSumit Saxena #include "mpi3mr_app.h"
81*2d1d418eSSumit Saxena 
82*2d1d418eSSumit Saxena static void mpi3mr_repost_reply_buf(struct mpi3mr_softc *sc,
83*2d1d418eSSumit Saxena 	U64 reply_dma);
84*2d1d418eSSumit Saxena static int mpi3mr_complete_admin_cmd(struct mpi3mr_softc *sc);
85*2d1d418eSSumit Saxena static void mpi3mr_port_enable_complete(struct mpi3mr_softc *sc,
86*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drvrcmd);
87*2d1d418eSSumit Saxena static void mpi3mr_flush_io(struct mpi3mr_softc *sc);
88*2d1d418eSSumit Saxena static int mpi3mr_issue_reset(struct mpi3mr_softc *sc, U16 reset_type,
89*2d1d418eSSumit Saxena 	U32 reset_reason);
90*2d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_softc *sc, U16 handle,
91*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdparam, U8 iou_rc);
92*2d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_softc *sc,
93*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd);
94*2d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_complete_tm(struct mpi3mr_softc *sc,
95*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd);
96*2d1d418eSSumit Saxena static void mpi3mr_send_evt_ack(struct mpi3mr_softc *sc, U8 event,
97*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdparam, U32 event_ctx);
98*2d1d418eSSumit Saxena static void mpi3mr_print_fault_info(struct mpi3mr_softc *sc);
99*2d1d418eSSumit Saxena static inline void mpi3mr_set_diagsave(struct mpi3mr_softc *sc);
100*2d1d418eSSumit Saxena static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code);
101*2d1d418eSSumit Saxena 
102*2d1d418eSSumit Saxena void
103*2d1d418eSSumit Saxena mpi3mr_hexdump(void *buf, int sz, int format)
104*2d1d418eSSumit Saxena {
105*2d1d418eSSumit Saxena         int i;
106*2d1d418eSSumit Saxena         U32 *buf_loc = (U32 *)buf;
107*2d1d418eSSumit Saxena 
108*2d1d418eSSumit Saxena         for (i = 0; i < (sz / sizeof(U32)); i++) {
109*2d1d418eSSumit Saxena                 if ((i % format) == 0) {
110*2d1d418eSSumit Saxena                         if (i != 0)
111*2d1d418eSSumit Saxena                                 printf("\n");
112*2d1d418eSSumit Saxena                         printf("%08x: ", (i * 4));
113*2d1d418eSSumit Saxena                 }
114*2d1d418eSSumit Saxena                 printf("%08x ", buf_loc[i]);
115*2d1d418eSSumit Saxena         }
116*2d1d418eSSumit Saxena         printf("\n");
117*2d1d418eSSumit Saxena }
118*2d1d418eSSumit Saxena 
119*2d1d418eSSumit Saxena void
120*2d1d418eSSumit Saxena init_completion(struct completion *completion)
121*2d1d418eSSumit Saxena {
122*2d1d418eSSumit Saxena 	completion->done = 0;
123*2d1d418eSSumit Saxena }
124*2d1d418eSSumit Saxena 
125*2d1d418eSSumit Saxena void
126*2d1d418eSSumit Saxena complete(struct completion *completion)
127*2d1d418eSSumit Saxena {
128*2d1d418eSSumit Saxena 	completion->done = 1;
129*2d1d418eSSumit Saxena 	wakeup(complete);
130*2d1d418eSSumit Saxena }
131*2d1d418eSSumit Saxena 
132*2d1d418eSSumit Saxena void wait_for_completion_timeout(struct completion *completion,
133*2d1d418eSSumit Saxena 	    U32 timeout)
134*2d1d418eSSumit Saxena {
135*2d1d418eSSumit Saxena 	U32 count = timeout * 1000;
136*2d1d418eSSumit Saxena 
137*2d1d418eSSumit Saxena 	while ((completion->done == 0) && count) {
138*2d1d418eSSumit Saxena                 DELAY(1000);
139*2d1d418eSSumit Saxena 		count--;
140*2d1d418eSSumit Saxena 	}
141*2d1d418eSSumit Saxena 
142*2d1d418eSSumit Saxena 	if (completion->done == 0) {
143*2d1d418eSSumit Saxena 		printf("%s: Command is timedout\n", __func__);
144*2d1d418eSSumit Saxena 		completion->done = 1;
145*2d1d418eSSumit Saxena 	}
146*2d1d418eSSumit Saxena }
147*2d1d418eSSumit Saxena void wait_for_completion_timeout_tm(struct completion *completion,
148*2d1d418eSSumit Saxena 	    U32 timeout, struct mpi3mr_softc *sc)
149*2d1d418eSSumit Saxena {
150*2d1d418eSSumit Saxena 	U32 count = timeout * 1000;
151*2d1d418eSSumit Saxena 
152*2d1d418eSSumit Saxena 	while ((completion->done == 0) && count) {
153*2d1d418eSSumit Saxena 		msleep(&sc->tm_chan, &sc->mpi3mr_mtx, PRIBIO,
154*2d1d418eSSumit Saxena 		       "TM command", 1 * hz);
155*2d1d418eSSumit Saxena 		count--;
156*2d1d418eSSumit Saxena 	}
157*2d1d418eSSumit Saxena 
158*2d1d418eSSumit Saxena 	if (completion->done == 0) {
159*2d1d418eSSumit Saxena 		printf("%s: Command is timedout\n", __func__);
160*2d1d418eSSumit Saxena 		completion->done = 1;
161*2d1d418eSSumit Saxena 	}
162*2d1d418eSSumit Saxena }
163*2d1d418eSSumit Saxena 
164*2d1d418eSSumit Saxena 
165*2d1d418eSSumit Saxena void
166*2d1d418eSSumit Saxena poll_for_command_completion(struct mpi3mr_softc *sc,
167*2d1d418eSSumit Saxena        struct mpi3mr_drvr_cmd *cmd, U16 wait)
168*2d1d418eSSumit Saxena {
169*2d1d418eSSumit Saxena 	int wait_time = wait * 1000;
170*2d1d418eSSumit Saxena        while (wait_time) {
171*2d1d418eSSumit Saxena                mpi3mr_complete_admin_cmd(sc);
172*2d1d418eSSumit Saxena                if (cmd->state & MPI3MR_CMD_COMPLETE)
173*2d1d418eSSumit Saxena                        break;
174*2d1d418eSSumit Saxena 	       DELAY(1000);
175*2d1d418eSSumit Saxena                wait_time--;
176*2d1d418eSSumit Saxena        }
177*2d1d418eSSumit Saxena }
178*2d1d418eSSumit Saxena 
179*2d1d418eSSumit Saxena /**
180*2d1d418eSSumit Saxena  * mpi3mr_trigger_snapdump - triggers firmware snapdump
181*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
182*2d1d418eSSumit Saxena  * @reason_code: reason code for the fault.
183*2d1d418eSSumit Saxena  *
184*2d1d418eSSumit Saxena  * This routine will trigger the snapdump and wait for it to
185*2d1d418eSSumit Saxena  * complete or timeout before it returns.
186*2d1d418eSSumit Saxena  * This will be called during initilaization time faults/resets/timeouts
187*2d1d418eSSumit Saxena  * before soft reset invocation.
188*2d1d418eSSumit Saxena  *
189*2d1d418eSSumit Saxena  * Return:  None.
190*2d1d418eSSumit Saxena  */
191*2d1d418eSSumit Saxena static void
192*2d1d418eSSumit Saxena mpi3mr_trigger_snapdump(struct mpi3mr_softc *sc, U32 reason_code)
193*2d1d418eSSumit Saxena {
194*2d1d418eSSumit Saxena 	U32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
195*2d1d418eSSumit Saxena 
196*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "snapdump triggered: reason code: %s\n",
197*2d1d418eSSumit Saxena 	    mpi3mr_reset_rc_name(reason_code));
198*2d1d418eSSumit Saxena 
199*2d1d418eSSumit Saxena 	mpi3mr_set_diagsave(sc);
200*2d1d418eSSumit Saxena 	mpi3mr_issue_reset(sc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
201*2d1d418eSSumit Saxena 			   reason_code);
202*2d1d418eSSumit Saxena 
203*2d1d418eSSumit Saxena 	do {
204*2d1d418eSSumit Saxena 		host_diagnostic = mpi3mr_regread(sc, MPI3_SYSIF_HOST_DIAG_OFFSET);
205*2d1d418eSSumit Saxena 		if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
206*2d1d418eSSumit Saxena 			break;
207*2d1d418eSSumit Saxena                 DELAY(100 * 1000);
208*2d1d418eSSumit Saxena 	} while (--timeout);
209*2d1d418eSSumit Saxena 
210*2d1d418eSSumit Saxena 	return;
211*2d1d418eSSumit Saxena }
212*2d1d418eSSumit Saxena 
213*2d1d418eSSumit Saxena /**
214*2d1d418eSSumit Saxena  * mpi3mr_check_rh_fault_ioc - check reset history and fault
215*2d1d418eSSumit Saxena  * controller
216*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
217*2d1d418eSSumit Saxena  * @reason_code, reason code for the fault.
218*2d1d418eSSumit Saxena  *
219*2d1d418eSSumit Saxena  * This routine will fault the controller with
220*2d1d418eSSumit Saxena  * the given reason code if it is not already in the fault or
221*2d1d418eSSumit Saxena  * not asynchronosuly reset. This will be used to handle
222*2d1d418eSSumit Saxena  * initilaization time faults/resets/timeout as in those cases
223*2d1d418eSSumit Saxena  * immediate soft reset invocation is not required.
224*2d1d418eSSumit Saxena  *
225*2d1d418eSSumit Saxena  * Return:  None.
226*2d1d418eSSumit Saxena  */
227*2d1d418eSSumit Saxena static void mpi3mr_check_rh_fault_ioc(struct mpi3mr_softc *sc, U32 reason_code)
228*2d1d418eSSumit Saxena {
229*2d1d418eSSumit Saxena 	U32 ioc_status;
230*2d1d418eSSumit Saxena 
231*2d1d418eSSumit Saxena 	if (sc->unrecoverable) {
232*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "controller is unrecoverable\n");
233*2d1d418eSSumit Saxena 		return;
234*2d1d418eSSumit Saxena 	}
235*2d1d418eSSumit Saxena 
236*2d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
237*2d1d418eSSumit Saxena 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
238*2d1d418eSSumit Saxena 	    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
239*2d1d418eSSumit Saxena 		mpi3mr_print_fault_info(sc);
240*2d1d418eSSumit Saxena 		return;
241*2d1d418eSSumit Saxena 	}
242*2d1d418eSSumit Saxena 
243*2d1d418eSSumit Saxena 	mpi3mr_trigger_snapdump(sc, reason_code);
244*2d1d418eSSumit Saxena 
245*2d1d418eSSumit Saxena 	return;
246*2d1d418eSSumit Saxena }
247*2d1d418eSSumit Saxena 
248*2d1d418eSSumit Saxena static void * mpi3mr_get_reply_virt_addr(struct mpi3mr_softc *sc,
249*2d1d418eSSumit Saxena     bus_addr_t phys_addr)
250*2d1d418eSSumit Saxena {
251*2d1d418eSSumit Saxena 	if (!phys_addr)
252*2d1d418eSSumit Saxena 		return NULL;
253*2d1d418eSSumit Saxena 	if ((phys_addr < sc->reply_buf_dma_min_address) ||
254*2d1d418eSSumit Saxena 	    (phys_addr > sc->reply_buf_dma_max_address))
255*2d1d418eSSumit Saxena 		return NULL;
256*2d1d418eSSumit Saxena 
257*2d1d418eSSumit Saxena 	return sc->reply_buf + (phys_addr - sc->reply_buf_phys);
258*2d1d418eSSumit Saxena }
259*2d1d418eSSumit Saxena 
260*2d1d418eSSumit Saxena static void * mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_softc *sc,
261*2d1d418eSSumit Saxena     bus_addr_t phys_addr)
262*2d1d418eSSumit Saxena {
263*2d1d418eSSumit Saxena 	if (!phys_addr)
264*2d1d418eSSumit Saxena 		return NULL;
265*2d1d418eSSumit Saxena 	return sc->sense_buf + (phys_addr - sc->sense_buf_phys);
266*2d1d418eSSumit Saxena }
267*2d1d418eSSumit Saxena 
268*2d1d418eSSumit Saxena static void mpi3mr_repost_reply_buf(struct mpi3mr_softc *sc,
269*2d1d418eSSumit Saxena     U64 reply_dma)
270*2d1d418eSSumit Saxena {
271*2d1d418eSSumit Saxena 	U32 old_idx = 0;
272*2d1d418eSSumit Saxena 
273*2d1d418eSSumit Saxena 	mtx_lock_spin(&sc->reply_free_q_lock);
274*2d1d418eSSumit Saxena 	old_idx  =  sc->reply_free_q_host_index;
275*2d1d418eSSumit Saxena 	sc->reply_free_q_host_index = ((sc->reply_free_q_host_index ==
276*2d1d418eSSumit Saxena 	    (sc->reply_free_q_sz - 1)) ? 0 :
277*2d1d418eSSumit Saxena 	    (sc->reply_free_q_host_index + 1));
278*2d1d418eSSumit Saxena 	sc->reply_free_q[old_idx] = reply_dma;
279*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_REPLY_FREE_HOST_INDEX_OFFSET,
280*2d1d418eSSumit Saxena 		sc->reply_free_q_host_index);
281*2d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->reply_free_q_lock);
282*2d1d418eSSumit Saxena }
283*2d1d418eSSumit Saxena 
284*2d1d418eSSumit Saxena static void mpi3mr_repost_sense_buf(struct mpi3mr_softc *sc,
285*2d1d418eSSumit Saxena     U64 sense_buf_phys)
286*2d1d418eSSumit Saxena {
287*2d1d418eSSumit Saxena 	U32 old_idx = 0;
288*2d1d418eSSumit Saxena 
289*2d1d418eSSumit Saxena 	mtx_lock_spin(&sc->sense_buf_q_lock);
290*2d1d418eSSumit Saxena 	old_idx  =  sc->sense_buf_q_host_index;
291*2d1d418eSSumit Saxena 	sc->sense_buf_q_host_index = ((sc->sense_buf_q_host_index ==
292*2d1d418eSSumit Saxena 	    (sc->sense_buf_q_sz - 1)) ? 0 :
293*2d1d418eSSumit Saxena 	    (sc->sense_buf_q_host_index + 1));
294*2d1d418eSSumit Saxena 	sc->sense_buf_q[old_idx] = sense_buf_phys;
295*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_SENSE_BUF_FREE_HOST_INDEX_OFFSET,
296*2d1d418eSSumit Saxena 		sc->sense_buf_q_host_index);
297*2d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->sense_buf_q_lock);
298*2d1d418eSSumit Saxena 
299*2d1d418eSSumit Saxena }
300*2d1d418eSSumit Saxena 
301*2d1d418eSSumit Saxena void mpi3mr_set_io_divert_for_all_vd_in_tg(struct mpi3mr_softc *sc,
302*2d1d418eSSumit Saxena 	struct mpi3mr_throttle_group_info *tg, U8 divert_value)
303*2d1d418eSSumit Saxena {
304*2d1d418eSSumit Saxena 	struct mpi3mr_target *target;
305*2d1d418eSSumit Saxena 
306*2d1d418eSSumit Saxena 	mtx_lock_spin(&sc->target_lock);
307*2d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) {
308*2d1d418eSSumit Saxena 		if (target->throttle_group == tg)
309*2d1d418eSSumit Saxena 			target->io_divert = divert_value;
310*2d1d418eSSumit Saxena 	}
311*2d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->target_lock);
312*2d1d418eSSumit Saxena }
313*2d1d418eSSumit Saxena 
314*2d1d418eSSumit Saxena /**
315*2d1d418eSSumit Saxena  * mpi3mr_submit_admin_cmd - Submit request to admin queue
316*2d1d418eSSumit Saxena  * @mrioc: Adapter reference
317*2d1d418eSSumit Saxena  * @admin_req: MPI3 request
318*2d1d418eSSumit Saxena  * @admin_req_sz: Request size
319*2d1d418eSSumit Saxena  *
320*2d1d418eSSumit Saxena  * Post the MPI3 request into admin request queue and
321*2d1d418eSSumit Saxena  * inform the controller, if the queue is full return
322*2d1d418eSSumit Saxena  * appropriate error.
323*2d1d418eSSumit Saxena  *
324*2d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failure.
325*2d1d418eSSumit Saxena  */
326*2d1d418eSSumit Saxena int mpi3mr_submit_admin_cmd(struct mpi3mr_softc *sc, void *admin_req,
327*2d1d418eSSumit Saxena     U16 admin_req_sz)
328*2d1d418eSSumit Saxena {
329*2d1d418eSSumit Saxena 	U16 areq_pi = 0, areq_ci = 0, max_entries = 0;
330*2d1d418eSSumit Saxena 	int retval = 0;
331*2d1d418eSSumit Saxena 	U8 *areq_entry;
332*2d1d418eSSumit Saxena 
333*2d1d418eSSumit Saxena 	mtx_lock_spin(&sc->admin_req_lock);
334*2d1d418eSSumit Saxena 	areq_pi = sc->admin_req_pi;
335*2d1d418eSSumit Saxena 	areq_ci = sc->admin_req_ci;
336*2d1d418eSSumit Saxena 	max_entries = sc->num_admin_reqs;
337*2d1d418eSSumit Saxena 
338*2d1d418eSSumit Saxena 	if (sc->unrecoverable)
339*2d1d418eSSumit Saxena 		return -EFAULT;
340*2d1d418eSSumit Saxena 
341*2d1d418eSSumit Saxena 	if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) &&
342*2d1d418eSSumit Saxena 					   (areq_pi == (max_entries - 1)))) {
343*2d1d418eSSumit Saxena 		printf(IOCNAME "AdminReqQ full condition detected\n",
344*2d1d418eSSumit Saxena 		    sc->name);
345*2d1d418eSSumit Saxena 		retval = -EAGAIN;
346*2d1d418eSSumit Saxena 		goto out;
347*2d1d418eSSumit Saxena 	}
348*2d1d418eSSumit Saxena 	areq_entry = (U8 *)sc->admin_req + (areq_pi *
349*2d1d418eSSumit Saxena 						     MPI3MR_AREQ_FRAME_SZ);
350*2d1d418eSSumit Saxena 	memset(areq_entry, 0, MPI3MR_AREQ_FRAME_SZ);
351*2d1d418eSSumit Saxena 	memcpy(areq_entry, (U8 *)admin_req, admin_req_sz);
352*2d1d418eSSumit Saxena 
353*2d1d418eSSumit Saxena 	if (++areq_pi == max_entries)
354*2d1d418eSSumit Saxena 		areq_pi = 0;
355*2d1d418eSSumit Saxena 	sc->admin_req_pi = areq_pi;
356*2d1d418eSSumit Saxena 
357*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REQ_Q_PI_OFFSET, sc->admin_req_pi);
358*2d1d418eSSumit Saxena 
359*2d1d418eSSumit Saxena out:
360*2d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->admin_req_lock);
361*2d1d418eSSumit Saxena 	return retval;
362*2d1d418eSSumit Saxena }
363*2d1d418eSSumit Saxena 
364*2d1d418eSSumit Saxena /**
365*2d1d418eSSumit Saxena  * mpi3mr_check_req_qfull - Check request queue is full or not
366*2d1d418eSSumit Saxena  * @op_req_q: Operational reply queue info
367*2d1d418eSSumit Saxena  *
368*2d1d418eSSumit Saxena  * Return: true when queue full, false otherwise.
369*2d1d418eSSumit Saxena  */
370*2d1d418eSSumit Saxena static inline bool
371*2d1d418eSSumit Saxena mpi3mr_check_req_qfull(struct mpi3mr_op_req_queue *op_req_q)
372*2d1d418eSSumit Saxena {
373*2d1d418eSSumit Saxena 	U16 pi, ci, max_entries;
374*2d1d418eSSumit Saxena 	bool is_qfull = false;
375*2d1d418eSSumit Saxena 
376*2d1d418eSSumit Saxena 	pi = op_req_q->pi;
377*2d1d418eSSumit Saxena 	ci = op_req_q->ci;
378*2d1d418eSSumit Saxena 	max_entries = op_req_q->num_reqs;
379*2d1d418eSSumit Saxena 
380*2d1d418eSSumit Saxena 	if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1))))
381*2d1d418eSSumit Saxena 		is_qfull = true;
382*2d1d418eSSumit Saxena 
383*2d1d418eSSumit Saxena 	return is_qfull;
384*2d1d418eSSumit Saxena }
385*2d1d418eSSumit Saxena 
386*2d1d418eSSumit Saxena /**
387*2d1d418eSSumit Saxena  * mpi3mr_submit_io - Post IO command to firmware
388*2d1d418eSSumit Saxena  * @sc:		      Adapter instance reference
389*2d1d418eSSumit Saxena  * @op_req_q:	      Operational Request queue reference
390*2d1d418eSSumit Saxena  * @req:	      MPT request data
391*2d1d418eSSumit Saxena  *
392*2d1d418eSSumit Saxena  * This function submits IO command to firmware.
393*2d1d418eSSumit Saxena  *
394*2d1d418eSSumit Saxena  * Return: Nothing
395*2d1d418eSSumit Saxena  */
396*2d1d418eSSumit Saxena int mpi3mr_submit_io(struct mpi3mr_softc *sc,
397*2d1d418eSSumit Saxena     struct mpi3mr_op_req_queue *op_req_q, U8 *req)
398*2d1d418eSSumit Saxena {
399*2d1d418eSSumit Saxena 	U16 pi, max_entries;
400*2d1d418eSSumit Saxena 	int retval = 0;
401*2d1d418eSSumit Saxena 	U8 *req_entry;
402*2d1d418eSSumit Saxena 	U16 req_sz = sc->facts.op_req_sz;
403*2d1d418eSSumit Saxena 	struct mpi3mr_irq_context *irq_ctx;
404*2d1d418eSSumit Saxena 
405*2d1d418eSSumit Saxena 	mtx_lock_spin(&op_req_q->q_lock);
406*2d1d418eSSumit Saxena 
407*2d1d418eSSumit Saxena 	pi = op_req_q->pi;
408*2d1d418eSSumit Saxena 	max_entries = op_req_q->num_reqs;
409*2d1d418eSSumit Saxena 	if (mpi3mr_check_req_qfull(op_req_q)) {
410*2d1d418eSSumit Saxena 		irq_ctx = &sc->irq_ctx[op_req_q->reply_qid - 1];
411*2d1d418eSSumit Saxena 		mpi3mr_complete_io_cmd(sc, irq_ctx);
412*2d1d418eSSumit Saxena 
413*2d1d418eSSumit Saxena 		if (mpi3mr_check_req_qfull(op_req_q)) {
414*2d1d418eSSumit Saxena 			printf(IOCNAME "OpReqQ full condition detected\n",
415*2d1d418eSSumit Saxena 				sc->name);
416*2d1d418eSSumit Saxena 			retval = -EBUSY;
417*2d1d418eSSumit Saxena 			goto out;
418*2d1d418eSSumit Saxena 		}
419*2d1d418eSSumit Saxena 	}
420*2d1d418eSSumit Saxena 
421*2d1d418eSSumit Saxena 	req_entry = (U8 *)op_req_q->q_base + (pi * req_sz);
422*2d1d418eSSumit Saxena 	memset(req_entry, 0, req_sz);
423*2d1d418eSSumit Saxena 	memcpy(req_entry, req, MPI3MR_AREQ_FRAME_SZ);
424*2d1d418eSSumit Saxena 	if (++pi == max_entries)
425*2d1d418eSSumit Saxena 		pi = 0;
426*2d1d418eSSumit Saxena 	op_req_q->pi = pi;
427*2d1d418eSSumit Saxena 
428*2d1d418eSSumit Saxena 	mpi3mr_atomic_inc(&sc->op_reply_q[op_req_q->reply_qid - 1].pend_ios);
429*2d1d418eSSumit Saxena 
430*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_OPER_REQ_Q_N_PI_OFFSET(op_req_q->qid), op_req_q->pi);
431*2d1d418eSSumit Saxena 	if (sc->mpi3mr_debug & MPI3MR_TRACE) {
432*2d1d418eSSumit Saxena 		device_printf(sc->mpi3mr_dev, "IO submission: QID:%d PI:0x%x\n", op_req_q->qid, op_req_q->pi);
433*2d1d418eSSumit Saxena 		mpi3mr_hexdump(req_entry, MPI3MR_AREQ_FRAME_SZ, 8);
434*2d1d418eSSumit Saxena 	}
435*2d1d418eSSumit Saxena 
436*2d1d418eSSumit Saxena out:
437*2d1d418eSSumit Saxena 	mtx_unlock_spin(&op_req_q->q_lock);
438*2d1d418eSSumit Saxena 	return retval;
439*2d1d418eSSumit Saxena }
440*2d1d418eSSumit Saxena 
441*2d1d418eSSumit Saxena inline void
442*2d1d418eSSumit Saxena mpi3mr_add_sg_single(void *paddr, U8 flags, U32 length,
443*2d1d418eSSumit Saxena 		     bus_addr_t dma_addr)
444*2d1d418eSSumit Saxena {
445*2d1d418eSSumit Saxena 	Mpi3SGESimple_t *sgel = paddr;
446*2d1d418eSSumit Saxena 
447*2d1d418eSSumit Saxena 	sgel->Flags = flags;
448*2d1d418eSSumit Saxena 	sgel->Length = (length);
449*2d1d418eSSumit Saxena 	sgel->Address = (U64)dma_addr;
450*2d1d418eSSumit Saxena }
451*2d1d418eSSumit Saxena 
452*2d1d418eSSumit Saxena void mpi3mr_build_zero_len_sge(void *paddr)
453*2d1d418eSSumit Saxena {
454*2d1d418eSSumit Saxena 	U8 sgl_flags = (MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE |
455*2d1d418eSSumit Saxena 		MPI3_SGE_FLAGS_DLAS_SYSTEM | MPI3_SGE_FLAGS_END_OF_LIST);
456*2d1d418eSSumit Saxena 
457*2d1d418eSSumit Saxena 	mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1);
458*2d1d418eSSumit Saxena 
459*2d1d418eSSumit Saxena }
460*2d1d418eSSumit Saxena 
461*2d1d418eSSumit Saxena void mpi3mr_enable_interrupts(struct mpi3mr_softc *sc)
462*2d1d418eSSumit Saxena {
463*2d1d418eSSumit Saxena 	sc->intr_enabled = 1;
464*2d1d418eSSumit Saxena }
465*2d1d418eSSumit Saxena 
466*2d1d418eSSumit Saxena void mpi3mr_disable_interrupts(struct mpi3mr_softc *sc)
467*2d1d418eSSumit Saxena {
468*2d1d418eSSumit Saxena 	sc->intr_enabled = 0;
469*2d1d418eSSumit Saxena }
470*2d1d418eSSumit Saxena 
471*2d1d418eSSumit Saxena void
472*2d1d418eSSumit Saxena mpi3mr_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
473*2d1d418eSSumit Saxena {
474*2d1d418eSSumit Saxena 	bus_addr_t *addr;
475*2d1d418eSSumit Saxena 
476*2d1d418eSSumit Saxena 	addr = arg;
477*2d1d418eSSumit Saxena 	*addr = segs[0].ds_addr;
478*2d1d418eSSumit Saxena }
479*2d1d418eSSumit Saxena 
480*2d1d418eSSumit Saxena static int mpi3mr_delete_op_reply_queue(struct mpi3mr_softc *sc, U16 qid)
481*2d1d418eSSumit Saxena {
482*2d1d418eSSumit Saxena 	Mpi3DeleteReplyQueueRequest_t delq_req;
483*2d1d418eSSumit Saxena 	struct mpi3mr_op_reply_queue *op_reply_q;
484*2d1d418eSSumit Saxena 	int retval = 0;
485*2d1d418eSSumit Saxena 
486*2d1d418eSSumit Saxena 
487*2d1d418eSSumit Saxena 	op_reply_q = &sc->op_reply_q[qid - 1];
488*2d1d418eSSumit Saxena 
489*2d1d418eSSumit Saxena 	if (!op_reply_q->qid)
490*2d1d418eSSumit Saxena 	{
491*2d1d418eSSumit Saxena 		retval = -1;
492*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: called with invalid Reply QID\n",
493*2d1d418eSSumit Saxena 		    sc->name);
494*2d1d418eSSumit Saxena 		goto out;
495*2d1d418eSSumit Saxena 	}
496*2d1d418eSSumit Saxena 
497*2d1d418eSSumit Saxena 	memset(&delq_req, 0, sizeof(delq_req));
498*2d1d418eSSumit Saxena 
499*2d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
500*2d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
501*2d1d418eSSumit Saxena 		retval = -1;
502*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: Init command is in use\n",
503*2d1d418eSSumit Saxena 		    sc->name);
504*2d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
505*2d1d418eSSumit Saxena 		goto out;
506*2d1d418eSSumit Saxena 	}
507*2d1d418eSSumit Saxena 
508*2d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
509*2d1d418eSSumit Saxena 		retval = -1;
510*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: Init command is in use\n",
511*2d1d418eSSumit Saxena 		    sc->name);
512*2d1d418eSSumit Saxena 		goto out;
513*2d1d418eSSumit Saxena 	}
514*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
515*2d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
516*2d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
517*2d1d418eSSumit Saxena 	delq_req.HostTag = MPI3MR_HOSTTAG_INITCMDS;
518*2d1d418eSSumit Saxena 	delq_req.Function = MPI3_FUNCTION_DELETE_REPLY_QUEUE;
519*2d1d418eSSumit Saxena 	delq_req.QueueID = qid;
520*2d1d418eSSumit Saxena 
521*2d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
522*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &delq_req, sizeof(delq_req));
523*2d1d418eSSumit Saxena 	if (retval) {
524*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: Admin Post failed\n",
525*2d1d418eSSumit Saxena 		    sc->name);
526*2d1d418eSSumit Saxena 		goto out_unlock;
527*2d1d418eSSumit Saxena 	}
528*2d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
529*2d1d418eSSumit Saxena 	    (MPI3MR_INTADMCMD_TIMEOUT));
530*2d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
531*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: command timed out\n",
532*2d1d418eSSumit Saxena 		    sc->name);
533*2d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
534*2d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_DELREPQ_TIMEOUT);
535*2d1d418eSSumit Saxena 		sc->unrecoverable = 1;
536*2d1d418eSSumit Saxena 
537*2d1d418eSSumit Saxena 		retval = -1;
538*2d1d418eSSumit Saxena 		goto out_unlock;
539*2d1d418eSSumit Saxena 	}
540*2d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
541*2d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
542*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: Failed IOCStatus(0x%04x) "
543*2d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
544*2d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
545*2d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
546*2d1d418eSSumit Saxena 		retval = -1;
547*2d1d418eSSumit Saxena 		goto out_unlock;
548*2d1d418eSSumit Saxena 	}
549*2d1d418eSSumit Saxena 	sc->irq_ctx[qid - 1].op_reply_q = NULL;
550*2d1d418eSSumit Saxena 
551*2d1d418eSSumit Saxena 	if (sc->op_reply_q[qid - 1].q_base_phys != 0)
552*2d1d418eSSumit Saxena 		bus_dmamap_unload(sc->op_reply_q[qid - 1].q_base_tag, sc->op_reply_q[qid - 1].q_base_dmamap);
553*2d1d418eSSumit Saxena 	if (sc->op_reply_q[qid - 1].q_base != NULL)
554*2d1d418eSSumit Saxena 		bus_dmamem_free(sc->op_reply_q[qid - 1].q_base_tag, sc->op_reply_q[qid - 1].q_base, sc->op_reply_q[qid - 1].q_base_dmamap);
555*2d1d418eSSumit Saxena 	if (sc->op_reply_q[qid - 1].q_base_tag != NULL)
556*2d1d418eSSumit Saxena 		bus_dma_tag_destroy(sc->op_reply_q[qid - 1].q_base_tag);
557*2d1d418eSSumit Saxena 
558*2d1d418eSSumit Saxena 	sc->op_reply_q[qid - 1].q_base = NULL;
559*2d1d418eSSumit Saxena 	sc->op_reply_q[qid - 1].qid = 0;
560*2d1d418eSSumit Saxena out_unlock:
561*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
562*2d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
563*2d1d418eSSumit Saxena out:
564*2d1d418eSSumit Saxena 	return retval;
565*2d1d418eSSumit Saxena }
566*2d1d418eSSumit Saxena 
567*2d1d418eSSumit Saxena /**
568*2d1d418eSSumit Saxena  * mpi3mr_create_op_reply_queue - create operational reply queue
569*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
570*2d1d418eSSumit Saxena  * @qid: operational reply queue id
571*2d1d418eSSumit Saxena  *
572*2d1d418eSSumit Saxena  * Create operatinal reply queue by issuing MPI request
573*2d1d418eSSumit Saxena  * through admin queue.
574*2d1d418eSSumit Saxena  *
575*2d1d418eSSumit Saxena  * Return:  0 on success, non-zero on failure.
576*2d1d418eSSumit Saxena  */
577*2d1d418eSSumit Saxena static int mpi3mr_create_op_reply_queue(struct mpi3mr_softc *sc, U16 qid)
578*2d1d418eSSumit Saxena {
579*2d1d418eSSumit Saxena 	Mpi3CreateReplyQueueRequest_t create_req;
580*2d1d418eSSumit Saxena 	struct mpi3mr_op_reply_queue *op_reply_q;
581*2d1d418eSSumit Saxena 	int retval = 0;
582*2d1d418eSSumit Saxena 	char q_lock_name[32];
583*2d1d418eSSumit Saxena 
584*2d1d418eSSumit Saxena 	op_reply_q = &sc->op_reply_q[qid - 1];
585*2d1d418eSSumit Saxena 
586*2d1d418eSSumit Saxena 	if (op_reply_q->qid)
587*2d1d418eSSumit Saxena 	{
588*2d1d418eSSumit Saxena 		retval = -1;
589*2d1d418eSSumit Saxena 		printf(IOCNAME "CreateRepQ: called for duplicate qid %d\n",
590*2d1d418eSSumit Saxena 		    sc->name, op_reply_q->qid);
591*2d1d418eSSumit Saxena 		return retval;
592*2d1d418eSSumit Saxena 	}
593*2d1d418eSSumit Saxena 
594*2d1d418eSSumit Saxena 	op_reply_q->ci = 0;
595*2d1d418eSSumit Saxena 	if (pci_get_revid(sc->mpi3mr_dev) == SAS4116_CHIP_REV_A0)
596*2d1d418eSSumit Saxena 		op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD_A0;
597*2d1d418eSSumit Saxena 	else
598*2d1d418eSSumit Saxena 		op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
599*2d1d418eSSumit Saxena 
600*2d1d418eSSumit Saxena 	op_reply_q->qsz = op_reply_q->num_replies * sc->op_reply_sz;
601*2d1d418eSSumit Saxena 	op_reply_q->ephase = 1;
602*2d1d418eSSumit Saxena 
603*2d1d418eSSumit Saxena         if (!op_reply_q->q_base) {
604*2d1d418eSSumit Saxena 		snprintf(q_lock_name, 32, "Reply Queue Lock[%d]", qid);
605*2d1d418eSSumit Saxena 		mtx_init(&op_reply_q->q_lock, q_lock_name, NULL, MTX_SPIN);
606*2d1d418eSSumit Saxena 
607*2d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
608*2d1d418eSSumit Saxena 					4, 0,			/* algnmnt, boundary */
609*2d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
610*2d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR,	/* highaddr */
611*2d1d418eSSumit Saxena 					NULL, NULL,		/* filter, filterarg */
612*2d1d418eSSumit Saxena 					op_reply_q->qsz,		/* maxsize */
613*2d1d418eSSumit Saxena 					1,			/* nsegments */
614*2d1d418eSSumit Saxena 					op_reply_q->qsz,		/* maxsegsize */
615*2d1d418eSSumit Saxena 					0,			/* flags */
616*2d1d418eSSumit Saxena 					NULL, NULL,		/* lockfunc, lockarg */
617*2d1d418eSSumit Saxena 					&op_reply_q->q_base_tag)) {
618*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Operational reply DMA tag\n");
619*2d1d418eSSumit Saxena 			return (ENOMEM);
620*2d1d418eSSumit Saxena 		}
621*2d1d418eSSumit Saxena 
622*2d1d418eSSumit Saxena 		if (bus_dmamem_alloc(op_reply_q->q_base_tag, (void **)&op_reply_q->q_base,
623*2d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &op_reply_q->q_base_dmamap)) {
624*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
625*2d1d418eSSumit Saxena 			return (ENOMEM);
626*2d1d418eSSumit Saxena 		}
627*2d1d418eSSumit Saxena 		bzero(op_reply_q->q_base, op_reply_q->qsz);
628*2d1d418eSSumit Saxena 		bus_dmamap_load(op_reply_q->q_base_tag, op_reply_q->q_base_dmamap, op_reply_q->q_base, op_reply_q->qsz,
629*2d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &op_reply_q->q_base_phys, 0);
630*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Operational Reply queue ID: %d phys addr= %#016jx virt_addr: %pa size= %d\n",
631*2d1d418eSSumit Saxena 		    qid, (uintmax_t)op_reply_q->q_base_phys, op_reply_q->q_base, op_reply_q->qsz);
632*2d1d418eSSumit Saxena 
633*2d1d418eSSumit Saxena 		if (!op_reply_q->q_base)
634*2d1d418eSSumit Saxena 		{
635*2d1d418eSSumit Saxena 			retval = -1;
636*2d1d418eSSumit Saxena 			printf(IOCNAME "CreateRepQ: memory alloc failed for qid %d\n",
637*2d1d418eSSumit Saxena 			    sc->name, qid);
638*2d1d418eSSumit Saxena 			goto out;
639*2d1d418eSSumit Saxena 		}
640*2d1d418eSSumit Saxena 	}
641*2d1d418eSSumit Saxena 
642*2d1d418eSSumit Saxena 	memset(&create_req, 0, sizeof(create_req));
643*2d1d418eSSumit Saxena 
644*2d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
645*2d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
646*2d1d418eSSumit Saxena 		retval = -1;
647*2d1d418eSSumit Saxena 		printf(IOCNAME "CreateRepQ: Init command is in use\n",
648*2d1d418eSSumit Saxena 		    sc->name);
649*2d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
650*2d1d418eSSumit Saxena 		goto out;
651*2d1d418eSSumit Saxena 	}
652*2d1d418eSSumit Saxena 
653*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
654*2d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
655*2d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
656*2d1d418eSSumit Saxena 	create_req.HostTag = MPI3MR_HOSTTAG_INITCMDS;
657*2d1d418eSSumit Saxena 	create_req.Function = MPI3_FUNCTION_CREATE_REPLY_QUEUE;
658*2d1d418eSSumit Saxena 	create_req.QueueID = qid;
659*2d1d418eSSumit Saxena 	create_req.Flags = MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE;
660*2d1d418eSSumit Saxena 	create_req.MSIxIndex = sc->irq_ctx[qid - 1].msix_index;
661*2d1d418eSSumit Saxena 	create_req.BaseAddress = (U64)op_reply_q->q_base_phys;
662*2d1d418eSSumit Saxena 	create_req.Size = op_reply_q->num_replies;
663*2d1d418eSSumit Saxena 
664*2d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
665*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &create_req,
666*2d1d418eSSumit Saxena 	    sizeof(create_req));
667*2d1d418eSSumit Saxena 	if (retval) {
668*2d1d418eSSumit Saxena 		printf(IOCNAME "CreateRepQ: Admin Post failed\n",
669*2d1d418eSSumit Saxena 		    sc->name);
670*2d1d418eSSumit Saxena 		goto out_unlock;
671*2d1d418eSSumit Saxena 	}
672*2d1d418eSSumit Saxena 
673*2d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
674*2d1d418eSSumit Saxena 	  	MPI3MR_INTADMCMD_TIMEOUT);
675*2d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
676*2d1d418eSSumit Saxena 		printf(IOCNAME "CreateRepQ: command timed out\n",
677*2d1d418eSSumit Saxena 		    sc->name);
678*2d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
679*2d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT);
680*2d1d418eSSumit Saxena 		sc->unrecoverable = 1;
681*2d1d418eSSumit Saxena 		retval = -1;
682*2d1d418eSSumit Saxena 		goto out_unlock;
683*2d1d418eSSumit Saxena 	}
684*2d1d418eSSumit Saxena 
685*2d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
686*2d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
687*2d1d418eSSumit Saxena 		printf(IOCNAME "CreateRepQ: Failed IOCStatus(0x%04x) "
688*2d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
689*2d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
690*2d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
691*2d1d418eSSumit Saxena 		retval = -1;
692*2d1d418eSSumit Saxena 		goto out_unlock;
693*2d1d418eSSumit Saxena 	}
694*2d1d418eSSumit Saxena 	op_reply_q->qid = qid;
695*2d1d418eSSumit Saxena 	sc->irq_ctx[qid - 1].op_reply_q = op_reply_q;
696*2d1d418eSSumit Saxena 
697*2d1d418eSSumit Saxena out_unlock:
698*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
699*2d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
700*2d1d418eSSumit Saxena out:
701*2d1d418eSSumit Saxena 	if (retval) {
702*2d1d418eSSumit Saxena 		if (op_reply_q->q_base_phys != 0)
703*2d1d418eSSumit Saxena 			bus_dmamap_unload(op_reply_q->q_base_tag, op_reply_q->q_base_dmamap);
704*2d1d418eSSumit Saxena 		if (op_reply_q->q_base != NULL)
705*2d1d418eSSumit Saxena 			bus_dmamem_free(op_reply_q->q_base_tag, op_reply_q->q_base, op_reply_q->q_base_dmamap);
706*2d1d418eSSumit Saxena 		if (op_reply_q->q_base_tag != NULL)
707*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(op_reply_q->q_base_tag);
708*2d1d418eSSumit Saxena 		op_reply_q->q_base = NULL;
709*2d1d418eSSumit Saxena 		op_reply_q->qid = 0;
710*2d1d418eSSumit Saxena 	}
711*2d1d418eSSumit Saxena 
712*2d1d418eSSumit Saxena 	return retval;
713*2d1d418eSSumit Saxena }
714*2d1d418eSSumit Saxena 
715*2d1d418eSSumit Saxena /**
716*2d1d418eSSumit Saxena  * mpi3mr_create_op_req_queue - create operational request queue
717*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
718*2d1d418eSSumit Saxena  * @req_qid: operational request queue id
719*2d1d418eSSumit Saxena  * @reply_qid: Reply queue ID
720*2d1d418eSSumit Saxena  *
721*2d1d418eSSumit Saxena  * Create operatinal request queue by issuing MPI request
722*2d1d418eSSumit Saxena  * through admin queue.
723*2d1d418eSSumit Saxena  *
724*2d1d418eSSumit Saxena  * Return:  0 on success, non-zero on failure.
725*2d1d418eSSumit Saxena  */
726*2d1d418eSSumit Saxena static int mpi3mr_create_op_req_queue(struct mpi3mr_softc *sc, U16 req_qid, U8 reply_qid)
727*2d1d418eSSumit Saxena {
728*2d1d418eSSumit Saxena 	Mpi3CreateRequestQueueRequest_t create_req;
729*2d1d418eSSumit Saxena 	struct mpi3mr_op_req_queue *op_req_q;
730*2d1d418eSSumit Saxena 	int retval = 0;
731*2d1d418eSSumit Saxena 	char q_lock_name[32];
732*2d1d418eSSumit Saxena 
733*2d1d418eSSumit Saxena 	op_req_q = &sc->op_req_q[req_qid - 1];
734*2d1d418eSSumit Saxena 
735*2d1d418eSSumit Saxena 	if (op_req_q->qid)
736*2d1d418eSSumit Saxena 	{
737*2d1d418eSSumit Saxena 		retval = -1;
738*2d1d418eSSumit Saxena 		printf(IOCNAME "CreateReqQ: called for duplicate qid %d\n",
739*2d1d418eSSumit Saxena 		    sc->name, op_req_q->qid);
740*2d1d418eSSumit Saxena 		return retval;
741*2d1d418eSSumit Saxena 	}
742*2d1d418eSSumit Saxena 
743*2d1d418eSSumit Saxena 	op_req_q->ci = 0;
744*2d1d418eSSumit Saxena 	op_req_q->pi = 0;
745*2d1d418eSSumit Saxena 	op_req_q->num_reqs = MPI3MR_OP_REQ_Q_QD;
746*2d1d418eSSumit Saxena 	op_req_q->qsz = op_req_q->num_reqs * sc->facts.op_req_sz;
747*2d1d418eSSumit Saxena 	op_req_q->reply_qid = reply_qid;
748*2d1d418eSSumit Saxena 
749*2d1d418eSSumit Saxena 	if (!op_req_q->q_base) {
750*2d1d418eSSumit Saxena 		snprintf(q_lock_name, 32, "Request Queue Lock[%d]", req_qid);
751*2d1d418eSSumit Saxena 		mtx_init(&op_req_q->q_lock, q_lock_name, NULL, MTX_SPIN);
752*2d1d418eSSumit Saxena 
753*2d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
754*2d1d418eSSumit Saxena 					4, 0,			/* algnmnt, boundary */
755*2d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
756*2d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR,	/* highaddr */
757*2d1d418eSSumit Saxena 					NULL, NULL,		/* filter, filterarg */
758*2d1d418eSSumit Saxena 					op_req_q->qsz,		/* maxsize */
759*2d1d418eSSumit Saxena 					1,			/* nsegments */
760*2d1d418eSSumit Saxena 					op_req_q->qsz,		/* maxsegsize */
761*2d1d418eSSumit Saxena 					0,			/* flags */
762*2d1d418eSSumit Saxena 					NULL, NULL,		/* lockfunc, lockarg */
763*2d1d418eSSumit Saxena 					&op_req_q->q_base_tag)) {
764*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
765*2d1d418eSSumit Saxena 			return (ENOMEM);
766*2d1d418eSSumit Saxena 		}
767*2d1d418eSSumit Saxena 
768*2d1d418eSSumit Saxena 		if (bus_dmamem_alloc(op_req_q->q_base_tag, (void **)&op_req_q->q_base,
769*2d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &op_req_q->q_base_dmamap)) {
770*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
771*2d1d418eSSumit Saxena 			return (ENOMEM);
772*2d1d418eSSumit Saxena 		}
773*2d1d418eSSumit Saxena 
774*2d1d418eSSumit Saxena 		bzero(op_req_q->q_base, op_req_q->qsz);
775*2d1d418eSSumit Saxena 
776*2d1d418eSSumit Saxena 		bus_dmamap_load(op_req_q->q_base_tag, op_req_q->q_base_dmamap, op_req_q->q_base, op_req_q->qsz,
777*2d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &op_req_q->q_base_phys, 0);
778*2d1d418eSSumit Saxena 
779*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Operational Request QID: %d phys addr= %#016jx virt addr= %pa size= %d associated Reply QID: %d\n",
780*2d1d418eSSumit Saxena 		    req_qid, (uintmax_t)op_req_q->q_base_phys, op_req_q->q_base, op_req_q->qsz, reply_qid);
781*2d1d418eSSumit Saxena 
782*2d1d418eSSumit Saxena 		if (!op_req_q->q_base) {
783*2d1d418eSSumit Saxena 			retval = -1;
784*2d1d418eSSumit Saxena 			printf(IOCNAME "CreateReqQ: memory alloc failed for qid %d\n",
785*2d1d418eSSumit Saxena 			    sc->name, req_qid);
786*2d1d418eSSumit Saxena 			goto out;
787*2d1d418eSSumit Saxena 		}
788*2d1d418eSSumit Saxena 	}
789*2d1d418eSSumit Saxena 
790*2d1d418eSSumit Saxena 	memset(&create_req, 0, sizeof(create_req));
791*2d1d418eSSumit Saxena 
792*2d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
793*2d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
794*2d1d418eSSumit Saxena 		retval = -1;
795*2d1d418eSSumit Saxena 		printf(IOCNAME "CreateReqQ: Init command is in use\n",
796*2d1d418eSSumit Saxena 		    sc->name);
797*2d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
798*2d1d418eSSumit Saxena 		goto out;
799*2d1d418eSSumit Saxena 	}
800*2d1d418eSSumit Saxena 
801*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
802*2d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
803*2d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
804*2d1d418eSSumit Saxena 	create_req.HostTag = MPI3MR_HOSTTAG_INITCMDS;
805*2d1d418eSSumit Saxena 	create_req.Function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE;
806*2d1d418eSSumit Saxena 	create_req.QueueID = req_qid;
807*2d1d418eSSumit Saxena 	create_req.Flags = 0;
808*2d1d418eSSumit Saxena 	create_req.ReplyQueueID = reply_qid;
809*2d1d418eSSumit Saxena 	create_req.BaseAddress = (U64)op_req_q->q_base_phys;
810*2d1d418eSSumit Saxena 	create_req.Size = op_req_q->num_reqs;
811*2d1d418eSSumit Saxena 
812*2d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
813*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &create_req,
814*2d1d418eSSumit Saxena 	    sizeof(create_req));
815*2d1d418eSSumit Saxena 	if (retval) {
816*2d1d418eSSumit Saxena 		printf(IOCNAME "CreateReqQ: Admin Post failed\n",
817*2d1d418eSSumit Saxena 		    sc->name);
818*2d1d418eSSumit Saxena 		goto out_unlock;
819*2d1d418eSSumit Saxena 	}
820*2d1d418eSSumit Saxena 
821*2d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
822*2d1d418eSSumit Saxena 	    (MPI3MR_INTADMCMD_TIMEOUT));
823*2d1d418eSSumit Saxena 
824*2d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
825*2d1d418eSSumit Saxena 		printf(IOCNAME "CreateReqQ: command timed out\n",
826*2d1d418eSSumit Saxena 		    sc->name);
827*2d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
828*2d1d418eSSumit Saxena 			MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT);
829*2d1d418eSSumit Saxena 		sc->unrecoverable = 1;
830*2d1d418eSSumit Saxena 		retval = -1;
831*2d1d418eSSumit Saxena 		goto out_unlock;
832*2d1d418eSSumit Saxena 	}
833*2d1d418eSSumit Saxena 
834*2d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
835*2d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
836*2d1d418eSSumit Saxena 		printf(IOCNAME "CreateReqQ: Failed IOCStatus(0x%04x) "
837*2d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
838*2d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
839*2d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
840*2d1d418eSSumit Saxena 		retval = -1;
841*2d1d418eSSumit Saxena 		goto out_unlock;
842*2d1d418eSSumit Saxena 	}
843*2d1d418eSSumit Saxena 	op_req_q->qid = req_qid;
844*2d1d418eSSumit Saxena 
845*2d1d418eSSumit Saxena out_unlock:
846*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
847*2d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
848*2d1d418eSSumit Saxena out:
849*2d1d418eSSumit Saxena 	if (retval) {
850*2d1d418eSSumit Saxena 		if (op_req_q->q_base_phys != 0)
851*2d1d418eSSumit Saxena 			bus_dmamap_unload(op_req_q->q_base_tag, op_req_q->q_base_dmamap);
852*2d1d418eSSumit Saxena 		if (op_req_q->q_base != NULL)
853*2d1d418eSSumit Saxena 			bus_dmamem_free(op_req_q->q_base_tag, op_req_q->q_base, op_req_q->q_base_dmamap);
854*2d1d418eSSumit Saxena 		if (op_req_q->q_base_tag != NULL)
855*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(op_req_q->q_base_tag);
856*2d1d418eSSumit Saxena 		op_req_q->q_base = NULL;
857*2d1d418eSSumit Saxena 		op_req_q->qid = 0;
858*2d1d418eSSumit Saxena 	}
859*2d1d418eSSumit Saxena 	return retval;
860*2d1d418eSSumit Saxena }
861*2d1d418eSSumit Saxena 
862*2d1d418eSSumit Saxena /**
863*2d1d418eSSumit Saxena  * mpi3mr_create_op_queues - create operational queues
864*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
865*2d1d418eSSumit Saxena  *
866*2d1d418eSSumit Saxena  * Create operatinal queues(request queues and reply queues).
867*2d1d418eSSumit Saxena  * Return:  0 on success, non-zero on failure.
868*2d1d418eSSumit Saxena  */
869*2d1d418eSSumit Saxena static int mpi3mr_create_op_queues(struct mpi3mr_softc *sc)
870*2d1d418eSSumit Saxena {
871*2d1d418eSSumit Saxena 	int retval = 0;
872*2d1d418eSSumit Saxena 	U16 num_queues = 0, i = 0, qid;
873*2d1d418eSSumit Saxena 
874*2d1d418eSSumit Saxena 	num_queues = min(sc->facts.max_op_reply_q,
875*2d1d418eSSumit Saxena 	    sc->facts.max_op_req_q);
876*2d1d418eSSumit Saxena 	num_queues = min(num_queues, sc->msix_count);
877*2d1d418eSSumit Saxena 
878*2d1d418eSSumit Saxena 	/*
879*2d1d418eSSumit Saxena 	 * During reset set the num_queues to the number of queues
880*2d1d418eSSumit Saxena 	 * that was set before the reset.
881*2d1d418eSSumit Saxena 	 */
882*2d1d418eSSumit Saxena 	if (sc->num_queues)
883*2d1d418eSSumit Saxena 		num_queues = sc->num_queues;
884*2d1d418eSSumit Saxena 
885*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "Trying to create %d Operational Q pairs\n",
886*2d1d418eSSumit Saxena 	    num_queues);
887*2d1d418eSSumit Saxena 
888*2d1d418eSSumit Saxena 	if (!sc->op_req_q) {
889*2d1d418eSSumit Saxena 		sc->op_req_q = malloc(sizeof(struct mpi3mr_op_req_queue) *
890*2d1d418eSSumit Saxena 		    num_queues, M_MPI3MR, M_NOWAIT | M_ZERO);
891*2d1d418eSSumit Saxena 
892*2d1d418eSSumit Saxena 		if (!sc->op_req_q) {
893*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to alloc memory for Request queue info\n");
894*2d1d418eSSumit Saxena 			retval = -1;
895*2d1d418eSSumit Saxena 			goto out_failed;
896*2d1d418eSSumit Saxena 		}
897*2d1d418eSSumit Saxena 	}
898*2d1d418eSSumit Saxena 
899*2d1d418eSSumit Saxena 	if (!sc->op_reply_q) {
900*2d1d418eSSumit Saxena 		sc->op_reply_q = malloc(sizeof(struct mpi3mr_op_reply_queue) * num_queues,
901*2d1d418eSSumit Saxena 			M_MPI3MR, M_NOWAIT | M_ZERO);
902*2d1d418eSSumit Saxena 
903*2d1d418eSSumit Saxena 		if (!sc->op_reply_q) {
904*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to alloc memory for Reply queue info\n");
905*2d1d418eSSumit Saxena 			retval = -1;
906*2d1d418eSSumit Saxena 			goto out_failed;
907*2d1d418eSSumit Saxena 		}
908*2d1d418eSSumit Saxena 	}
909*2d1d418eSSumit Saxena 
910*2d1d418eSSumit Saxena 	sc->num_hosttag_op_req_q = (sc->max_host_ios + 1) / num_queues;
911*2d1d418eSSumit Saxena 
912*2d1d418eSSumit Saxena 	/*Operational Request and reply queue ID starts with 1*/
913*2d1d418eSSumit Saxena 	for (i = 0; i < num_queues; i++) {
914*2d1d418eSSumit Saxena 		qid = i + 1;
915*2d1d418eSSumit Saxena 		if (mpi3mr_create_op_reply_queue(sc, qid)) {
916*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to create Reply queue %d\n",
917*2d1d418eSSumit Saxena 			    qid);
918*2d1d418eSSumit Saxena 			break;
919*2d1d418eSSumit Saxena 		}
920*2d1d418eSSumit Saxena 		if (mpi3mr_create_op_req_queue(sc, qid,
921*2d1d418eSSumit Saxena 		    sc->op_reply_q[qid - 1].qid)) {
922*2d1d418eSSumit Saxena 			mpi3mr_delete_op_reply_queue(sc, qid);
923*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to create Request queue %d\n",
924*2d1d418eSSumit Saxena 			    qid);
925*2d1d418eSSumit Saxena 			break;
926*2d1d418eSSumit Saxena 		}
927*2d1d418eSSumit Saxena 
928*2d1d418eSSumit Saxena 	}
929*2d1d418eSSumit Saxena 
930*2d1d418eSSumit Saxena 	/* Not even one queue is created successfully*/
931*2d1d418eSSumit Saxena         if (i == 0) {
932*2d1d418eSSumit Saxena                 retval = -1;
933*2d1d418eSSumit Saxena                 goto out_failed;
934*2d1d418eSSumit Saxena         }
935*2d1d418eSSumit Saxena 
936*2d1d418eSSumit Saxena 	if (!sc->num_queues) {
937*2d1d418eSSumit Saxena 		sc->num_queues = i;
938*2d1d418eSSumit Saxena 	} else {
939*2d1d418eSSumit Saxena 		if (num_queues != i) {
940*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Number of queues (%d) post reset are not same as"
941*2d1d418eSSumit Saxena 					"queues allocated (%d) during driver init\n", i, num_queues);
942*2d1d418eSSumit Saxena 			goto out_failed;
943*2d1d418eSSumit Saxena 		}
944*2d1d418eSSumit Saxena 	}
945*2d1d418eSSumit Saxena 
946*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "Successfully created %d Operational Queue pairs\n",
947*2d1d418eSSumit Saxena 	    sc->num_queues);
948*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "Request Queue QD: %d Reply queue QD: %d\n",
949*2d1d418eSSumit Saxena 	    sc->op_req_q[0].num_reqs, sc->op_reply_q[0].num_replies);
950*2d1d418eSSumit Saxena 
951*2d1d418eSSumit Saxena 	return retval;
952*2d1d418eSSumit Saxena out_failed:
953*2d1d418eSSumit Saxena 	if (sc->op_req_q) {
954*2d1d418eSSumit Saxena 		free(sc->op_req_q, M_MPI3MR);
955*2d1d418eSSumit Saxena 		sc->op_req_q = NULL;
956*2d1d418eSSumit Saxena 	}
957*2d1d418eSSumit Saxena 	if (sc->op_reply_q) {
958*2d1d418eSSumit Saxena 		free(sc->op_reply_q, M_MPI3MR);
959*2d1d418eSSumit Saxena 		sc->op_reply_q = NULL;
960*2d1d418eSSumit Saxena 	}
961*2d1d418eSSumit Saxena 	return retval;
962*2d1d418eSSumit Saxena }
963*2d1d418eSSumit Saxena 
964*2d1d418eSSumit Saxena /**
965*2d1d418eSSumit Saxena  * mpi3mr_setup_admin_qpair - Setup admin queue pairs
966*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
967*2d1d418eSSumit Saxena  *
968*2d1d418eSSumit Saxena  * Allocation and setup admin queues(request queues and reply queues).
969*2d1d418eSSumit Saxena  * Return:  0 on success, non-zero on failure.
970*2d1d418eSSumit Saxena  */
971*2d1d418eSSumit Saxena static int mpi3mr_setup_admin_qpair(struct mpi3mr_softc *sc)
972*2d1d418eSSumit Saxena {
973*2d1d418eSSumit Saxena 	int retval = 0;
974*2d1d418eSSumit Saxena 	U32 num_adm_entries = 0;
975*2d1d418eSSumit Saxena 
976*2d1d418eSSumit Saxena 	sc->admin_req_q_sz = MPI3MR_AREQQ_SIZE;
977*2d1d418eSSumit Saxena 	sc->num_admin_reqs = sc->admin_req_q_sz / MPI3MR_AREQ_FRAME_SZ;
978*2d1d418eSSumit Saxena 	sc->admin_req_ci = sc->admin_req_pi = 0;
979*2d1d418eSSumit Saxena 
980*2d1d418eSSumit Saxena 	sc->admin_reply_q_sz = MPI3MR_AREPQ_SIZE;
981*2d1d418eSSumit Saxena 	sc->num_admin_replies = sc->admin_reply_q_sz/ MPI3MR_AREP_FRAME_SZ;
982*2d1d418eSSumit Saxena 	sc->admin_reply_ci = 0;
983*2d1d418eSSumit Saxena 	sc->admin_reply_ephase = 1;
984*2d1d418eSSumit Saxena 
985*2d1d418eSSumit Saxena 	if (!sc->admin_req) {
986*2d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
987*2d1d418eSSumit Saxena 					4, 0,			/* algnmnt, boundary */
988*2d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
989*2d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR,	/* highaddr */
990*2d1d418eSSumit Saxena 					NULL, NULL,		/* filter, filterarg */
991*2d1d418eSSumit Saxena 					sc->admin_req_q_sz,	/* maxsize */
992*2d1d418eSSumit Saxena 					1,			/* nsegments */
993*2d1d418eSSumit Saxena 					sc->admin_req_q_sz,	/* maxsegsize */
994*2d1d418eSSumit Saxena 					0,			/* flags */
995*2d1d418eSSumit Saxena 					NULL, NULL,		/* lockfunc, lockarg */
996*2d1d418eSSumit Saxena 					&sc->admin_req_tag)) {
997*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
998*2d1d418eSSumit Saxena 			return (ENOMEM);
999*2d1d418eSSumit Saxena 		}
1000*2d1d418eSSumit Saxena 
1001*2d1d418eSSumit Saxena 		if (bus_dmamem_alloc(sc->admin_req_tag, (void **)&sc->admin_req,
1002*2d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &sc->admin_req_dmamap)) {
1003*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
1004*2d1d418eSSumit Saxena 			return (ENOMEM);
1005*2d1d418eSSumit Saxena 		}
1006*2d1d418eSSumit Saxena 		bzero(sc->admin_req, sc->admin_req_q_sz);
1007*2d1d418eSSumit Saxena 		bus_dmamap_load(sc->admin_req_tag, sc->admin_req_dmamap, sc->admin_req, sc->admin_req_q_sz,
1008*2d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &sc->admin_req_phys, 0);
1009*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Admin Req queue phys addr= %#016jx size= %d\n",
1010*2d1d418eSSumit Saxena 		    (uintmax_t)sc->admin_req_phys, sc->admin_req_q_sz);
1011*2d1d418eSSumit Saxena 
1012*2d1d418eSSumit Saxena 		if (!sc->admin_req)
1013*2d1d418eSSumit Saxena 		{
1014*2d1d418eSSumit Saxena 			retval = -1;
1015*2d1d418eSSumit Saxena 			printf(IOCNAME "Memory alloc for AdminReqQ: failed\n",
1016*2d1d418eSSumit Saxena 			    sc->name);
1017*2d1d418eSSumit Saxena 			goto out_failed;
1018*2d1d418eSSumit Saxena 		}
1019*2d1d418eSSumit Saxena 	}
1020*2d1d418eSSumit Saxena 
1021*2d1d418eSSumit Saxena 	if (!sc->admin_reply) {
1022*2d1d418eSSumit Saxena 		mtx_init(&sc->admin_reply_lock, "Admin Reply Queue Lock", NULL, MTX_SPIN);
1023*2d1d418eSSumit Saxena 
1024*2d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
1025*2d1d418eSSumit Saxena 					4, 0,			/* algnmnt, boundary */
1026*2d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
1027*2d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR,	/* highaddr */
1028*2d1d418eSSumit Saxena 					NULL, NULL,		/* filter, filterarg */
1029*2d1d418eSSumit Saxena 					sc->admin_reply_q_sz,	/* maxsize */
1030*2d1d418eSSumit Saxena 					1,			/* nsegments */
1031*2d1d418eSSumit Saxena 					sc->admin_reply_q_sz,	/* maxsegsize */
1032*2d1d418eSSumit Saxena 					0,			/* flags */
1033*2d1d418eSSumit Saxena 					NULL, NULL,		/* lockfunc, lockarg */
1034*2d1d418eSSumit Saxena 					&sc->admin_reply_tag)) {
1035*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate reply DMA tag\n");
1036*2d1d418eSSumit Saxena 			return (ENOMEM);
1037*2d1d418eSSumit Saxena 		}
1038*2d1d418eSSumit Saxena 
1039*2d1d418eSSumit Saxena 		if (bus_dmamem_alloc(sc->admin_reply_tag, (void **)&sc->admin_reply,
1040*2d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &sc->admin_reply_dmamap)) {
1041*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
1042*2d1d418eSSumit Saxena 			return (ENOMEM);
1043*2d1d418eSSumit Saxena 		}
1044*2d1d418eSSumit Saxena 		bzero(sc->admin_reply, sc->admin_reply_q_sz);
1045*2d1d418eSSumit Saxena 		bus_dmamap_load(sc->admin_reply_tag, sc->admin_reply_dmamap, sc->admin_reply, sc->admin_reply_q_sz,
1046*2d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &sc->admin_reply_phys, 0);
1047*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Admin Reply queue phys addr= %#016jx size= %d\n",
1048*2d1d418eSSumit Saxena 		    (uintmax_t)sc->admin_reply_phys, sc->admin_req_q_sz);
1049*2d1d418eSSumit Saxena 
1050*2d1d418eSSumit Saxena 
1051*2d1d418eSSumit Saxena 		if (!sc->admin_reply)
1052*2d1d418eSSumit Saxena 		{
1053*2d1d418eSSumit Saxena 			retval = -1;
1054*2d1d418eSSumit Saxena 			printf(IOCNAME "Memory alloc for AdminRepQ: failed\n",
1055*2d1d418eSSumit Saxena 			    sc->name);
1056*2d1d418eSSumit Saxena 			goto out_failed;
1057*2d1d418eSSumit Saxena 		}
1058*2d1d418eSSumit Saxena 	}
1059*2d1d418eSSumit Saxena 
1060*2d1d418eSSumit Saxena 	num_adm_entries = (sc->num_admin_replies << 16) |
1061*2d1d418eSSumit Saxena 				(sc->num_admin_reqs);
1062*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_OFFSET, num_adm_entries);
1063*2d1d418eSSumit Saxena 	mpi3mr_regwrite64(sc, MPI3_SYSIF_ADMIN_REQ_Q_ADDR_LOW_OFFSET, sc->admin_req_phys);
1064*2d1d418eSSumit Saxena 	mpi3mr_regwrite64(sc, MPI3_SYSIF_ADMIN_REPLY_Q_ADDR_LOW_OFFSET, sc->admin_reply_phys);
1065*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REQ_Q_PI_OFFSET, sc->admin_req_pi);
1066*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REPLY_Q_CI_OFFSET, sc->admin_reply_ci);
1067*2d1d418eSSumit Saxena 
1068*2d1d418eSSumit Saxena 	return retval;
1069*2d1d418eSSumit Saxena 
1070*2d1d418eSSumit Saxena out_failed:
1071*2d1d418eSSumit Saxena 	/* Free Admin reply*/
1072*2d1d418eSSumit Saxena 	if (sc->admin_reply_phys)
1073*2d1d418eSSumit Saxena 		bus_dmamap_unload(sc->admin_reply_tag, sc->admin_reply_dmamap);
1074*2d1d418eSSumit Saxena 
1075*2d1d418eSSumit Saxena 	if (sc->admin_reply != NULL)
1076*2d1d418eSSumit Saxena 		bus_dmamem_free(sc->admin_reply_tag, sc->admin_reply,
1077*2d1d418eSSumit Saxena 		    sc->admin_reply_dmamap);
1078*2d1d418eSSumit Saxena 
1079*2d1d418eSSumit Saxena 	if (sc->admin_reply_tag != NULL)
1080*2d1d418eSSumit Saxena 		bus_dma_tag_destroy(sc->admin_reply_tag);
1081*2d1d418eSSumit Saxena 
1082*2d1d418eSSumit Saxena 	/* Free Admin request*/
1083*2d1d418eSSumit Saxena 	if (sc->admin_req_phys)
1084*2d1d418eSSumit Saxena 		bus_dmamap_unload(sc->admin_req_tag, sc->admin_req_dmamap);
1085*2d1d418eSSumit Saxena 
1086*2d1d418eSSumit Saxena 	if (sc->admin_req != NULL)
1087*2d1d418eSSumit Saxena 		bus_dmamem_free(sc->admin_req_tag, sc->admin_req,
1088*2d1d418eSSumit Saxena 		    sc->admin_req_dmamap);
1089*2d1d418eSSumit Saxena 
1090*2d1d418eSSumit Saxena 	if (sc->admin_req_tag != NULL)
1091*2d1d418eSSumit Saxena 		bus_dma_tag_destroy(sc->admin_req_tag);
1092*2d1d418eSSumit Saxena 
1093*2d1d418eSSumit Saxena 	return retval;
1094*2d1d418eSSumit Saxena }
1095*2d1d418eSSumit Saxena 
1096*2d1d418eSSumit Saxena /**
1097*2d1d418eSSumit Saxena  * mpi3mr_print_fault_info - Display fault information
1098*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
1099*2d1d418eSSumit Saxena  *
1100*2d1d418eSSumit Saxena  * Display the controller fault information if there is a
1101*2d1d418eSSumit Saxena  * controller fault.
1102*2d1d418eSSumit Saxena  *
1103*2d1d418eSSumit Saxena  * Return: Nothing.
1104*2d1d418eSSumit Saxena  */
1105*2d1d418eSSumit Saxena static void mpi3mr_print_fault_info(struct mpi3mr_softc *sc)
1106*2d1d418eSSumit Saxena {
1107*2d1d418eSSumit Saxena 	U32 ioc_status, code, code1, code2, code3;
1108*2d1d418eSSumit Saxena 
1109*2d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
1110*2d1d418eSSumit Saxena 
1111*2d1d418eSSumit Saxena 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
1112*2d1d418eSSumit Saxena 		code = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_OFFSET) &
1113*2d1d418eSSumit Saxena 			MPI3_SYSIF_FAULT_CODE_MASK;
1114*2d1d418eSSumit Saxena 		code1 = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_INFO0_OFFSET);
1115*2d1d418eSSumit Saxena 		code2 = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_INFO1_OFFSET);
1116*2d1d418eSSumit Saxena 		code3 = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_INFO2_OFFSET);
1117*2d1d418eSSumit Saxena 		printf(IOCNAME "fault codes 0x%04x:0x%04x:0x%04x:0x%04x\n",
1118*2d1d418eSSumit Saxena 		    sc->name, code, code1, code2, code3);
1119*2d1d418eSSumit Saxena 	}
1120*2d1d418eSSumit Saxena }
1121*2d1d418eSSumit Saxena 
1122*2d1d418eSSumit Saxena enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_softc *sc)
1123*2d1d418eSSumit Saxena {
1124*2d1d418eSSumit Saxena 	U32 ioc_status, ioc_control;
1125*2d1d418eSSumit Saxena 	U8 ready, enabled;
1126*2d1d418eSSumit Saxena 
1127*2d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
1128*2d1d418eSSumit Saxena 	ioc_control = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
1129*2d1d418eSSumit Saxena 
1130*2d1d418eSSumit Saxena 	if(sc->unrecoverable)
1131*2d1d418eSSumit Saxena 		return MRIOC_STATE_UNRECOVERABLE;
1132*2d1d418eSSumit Saxena 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)
1133*2d1d418eSSumit Saxena 		return MRIOC_STATE_FAULT;
1134*2d1d418eSSumit Saxena 
1135*2d1d418eSSumit Saxena 	ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY);
1136*2d1d418eSSumit Saxena 	enabled = (ioc_control & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC);
1137*2d1d418eSSumit Saxena 
1138*2d1d418eSSumit Saxena 	if (ready && enabled)
1139*2d1d418eSSumit Saxena 		return MRIOC_STATE_READY;
1140*2d1d418eSSumit Saxena 	if ((!ready) && (!enabled))
1141*2d1d418eSSumit Saxena 		return MRIOC_STATE_RESET;
1142*2d1d418eSSumit Saxena 	if ((!ready) && (enabled))
1143*2d1d418eSSumit Saxena 		return MRIOC_STATE_BECOMING_READY;
1144*2d1d418eSSumit Saxena 
1145*2d1d418eSSumit Saxena 	return MRIOC_STATE_RESET_REQUESTED;
1146*2d1d418eSSumit Saxena }
1147*2d1d418eSSumit Saxena 
1148*2d1d418eSSumit Saxena static inline void mpi3mr_clear_resethistory(struct mpi3mr_softc *sc)
1149*2d1d418eSSumit Saxena {
1150*2d1d418eSSumit Saxena         U32 ioc_status;
1151*2d1d418eSSumit Saxena 
1152*2d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
1153*2d1d418eSSumit Saxena         if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
1154*2d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_STATUS_OFFSET, ioc_status);
1155*2d1d418eSSumit Saxena 
1156*2d1d418eSSumit Saxena }
1157*2d1d418eSSumit Saxena 
1158*2d1d418eSSumit Saxena /**
1159*2d1d418eSSumit Saxena  * mpi3mr_mur_ioc - Message unit Reset handler
1160*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
1161*2d1d418eSSumit Saxena  * @reset_reason: Reset reason code
1162*2d1d418eSSumit Saxena  *
1163*2d1d418eSSumit Saxena  * Issue Message unit Reset to the controller and wait for it to
1164*2d1d418eSSumit Saxena  * be complete.
1165*2d1d418eSSumit Saxena  *
1166*2d1d418eSSumit Saxena  * Return: 0 on success, -1 on failure.
1167*2d1d418eSSumit Saxena  */
1168*2d1d418eSSumit Saxena static int mpi3mr_mur_ioc(struct mpi3mr_softc *sc, U32 reset_reason)
1169*2d1d418eSSumit Saxena {
1170*2d1d418eSSumit Saxena         U32 ioc_config, timeout, ioc_status;
1171*2d1d418eSSumit Saxena         int retval = -1;
1172*2d1d418eSSumit Saxena 
1173*2d1d418eSSumit Saxena         mpi3mr_dprint(sc, MPI3MR_INFO, "Issuing Message Unit Reset(MUR)\n");
1174*2d1d418eSSumit Saxena         if (sc->unrecoverable) {
1175*2d1d418eSSumit Saxena                 mpi3mr_dprint(sc, MPI3MR_ERROR, "IOC is unrecoverable MUR not issued\n");
1176*2d1d418eSSumit Saxena                 return retval;
1177*2d1d418eSSumit Saxena         }
1178*2d1d418eSSumit Saxena         mpi3mr_clear_resethistory(sc);
1179*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_SCRATCHPAD0_OFFSET, reset_reason);
1180*2d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
1181*2d1d418eSSumit Saxena         ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
1182*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
1183*2d1d418eSSumit Saxena 
1184*2d1d418eSSumit Saxena         timeout = MPI3MR_MUR_TIMEOUT * 10;
1185*2d1d418eSSumit Saxena         do {
1186*2d1d418eSSumit Saxena 		ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
1187*2d1d418eSSumit Saxena                 if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
1188*2d1d418eSSumit Saxena                         mpi3mr_clear_resethistory(sc);
1189*2d1d418eSSumit Saxena 			ioc_config =
1190*2d1d418eSSumit Saxena 				mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
1191*2d1d418eSSumit Saxena                         if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
1192*2d1d418eSSumit Saxena                             (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
1193*2d1d418eSSumit Saxena                             (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) {
1194*2d1d418eSSumit Saxena                                 retval = 0;
1195*2d1d418eSSumit Saxena                                 break;
1196*2d1d418eSSumit Saxena                         }
1197*2d1d418eSSumit Saxena                 }
1198*2d1d418eSSumit Saxena                 DELAY(100 * 1000);
1199*2d1d418eSSumit Saxena         } while (--timeout);
1200*2d1d418eSSumit Saxena 
1201*2d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
1202*2d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
1203*2d1d418eSSumit Saxena 
1204*2d1d418eSSumit Saxena         mpi3mr_dprint(sc, MPI3MR_INFO, "IOC Status/Config after %s MUR is (0x%x)/(0x%x)\n",
1205*2d1d418eSSumit Saxena                 !retval ? "successful":"failed", ioc_status, ioc_config);
1206*2d1d418eSSumit Saxena         return retval;
1207*2d1d418eSSumit Saxena }
1208*2d1d418eSSumit Saxena 
1209*2d1d418eSSumit Saxena /**
1210*2d1d418eSSumit Saxena  * mpi3mr_bring_ioc_ready - Bring controller to ready state
1211*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
1212*2d1d418eSSumit Saxena  *
1213*2d1d418eSSumit Saxena  * Set Enable IOC bit in IOC configuration register and wait for
1214*2d1d418eSSumit Saxena  * the controller to become ready.
1215*2d1d418eSSumit Saxena  *
1216*2d1d418eSSumit Saxena  * Return: 0 on success, appropriate error on failure.
1217*2d1d418eSSumit Saxena  */
1218*2d1d418eSSumit Saxena static int mpi3mr_bring_ioc_ready(struct mpi3mr_softc *sc)
1219*2d1d418eSSumit Saxena {
1220*2d1d418eSSumit Saxena         U32 ioc_config, timeout;
1221*2d1d418eSSumit Saxena         enum mpi3mr_iocstate current_state;
1222*2d1d418eSSumit Saxena 
1223*2d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
1224*2d1d418eSSumit Saxena         ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
1225*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
1226*2d1d418eSSumit Saxena 
1227*2d1d418eSSumit Saxena         timeout = sc->ready_timeout * 10;
1228*2d1d418eSSumit Saxena         do {
1229*2d1d418eSSumit Saxena                 current_state = mpi3mr_get_iocstate(sc);
1230*2d1d418eSSumit Saxena                 if (current_state == MRIOC_STATE_READY)
1231*2d1d418eSSumit Saxena                         return 0;
1232*2d1d418eSSumit Saxena                 DELAY(100 * 1000);
1233*2d1d418eSSumit Saxena         } while (--timeout);
1234*2d1d418eSSumit Saxena 
1235*2d1d418eSSumit Saxena         return -1;
1236*2d1d418eSSumit Saxena }
1237*2d1d418eSSumit Saxena 
1238*2d1d418eSSumit Saxena static const struct {
1239*2d1d418eSSumit Saxena 	enum mpi3mr_iocstate value;
1240*2d1d418eSSumit Saxena 	char *name;
1241*2d1d418eSSumit Saxena } mrioc_states[] = {
1242*2d1d418eSSumit Saxena 	{ MRIOC_STATE_READY, "ready" },
1243*2d1d418eSSumit Saxena 	{ MRIOC_STATE_FAULT, "fault" },
1244*2d1d418eSSumit Saxena 	{ MRIOC_STATE_RESET, "reset" },
1245*2d1d418eSSumit Saxena 	{ MRIOC_STATE_BECOMING_READY, "becoming ready" },
1246*2d1d418eSSumit Saxena 	{ MRIOC_STATE_RESET_REQUESTED, "reset requested" },
1247*2d1d418eSSumit Saxena 	{ MRIOC_STATE_COUNT, "Count" },
1248*2d1d418eSSumit Saxena };
1249*2d1d418eSSumit Saxena 
1250*2d1d418eSSumit Saxena static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)
1251*2d1d418eSSumit Saxena {
1252*2d1d418eSSumit Saxena 	int i;
1253*2d1d418eSSumit Saxena 	char *name = NULL;
1254*2d1d418eSSumit Saxena 
1255*2d1d418eSSumit Saxena 	for (i = 0; i < MRIOC_STATE_COUNT; i++) {
1256*2d1d418eSSumit Saxena 		if (mrioc_states[i].value == mrioc_state){
1257*2d1d418eSSumit Saxena 			name = mrioc_states[i].name;
1258*2d1d418eSSumit Saxena 			break;
1259*2d1d418eSSumit Saxena 		}
1260*2d1d418eSSumit Saxena 	}
1261*2d1d418eSSumit Saxena 	return name;
1262*2d1d418eSSumit Saxena }
1263*2d1d418eSSumit Saxena 
1264*2d1d418eSSumit Saxena /* Reset reason to name mapper structure*/
1265*2d1d418eSSumit Saxena static const struct {
1266*2d1d418eSSumit Saxena 	enum mpi3mr_reset_reason value;
1267*2d1d418eSSumit Saxena 	char *name;
1268*2d1d418eSSumit Saxena } mpi3mr_reset_reason_codes[] = {
1269*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" },
1270*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_FAULT_WATCH, "fault" },
1271*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_IOCTL, "application" },
1272*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_EH_HOS, "error handling" },
1273*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" },
1274*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_IOCTL_TIMEOUT, "IOCTL timeout" },
1275*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_SCSIIO_TIMEOUT, "SCSIIO timeout" },
1276*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" },
1277*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" },
1278*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" },
1279*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" },
1280*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" },
1281*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" },
1282*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" },
1283*2d1d418eSSumit Saxena 	{
1284*2d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT,
1285*2d1d418eSSumit Saxena 		"create request queue timeout"
1286*2d1d418eSSumit Saxena 	},
1287*2d1d418eSSumit Saxena 	{
1288*2d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT,
1289*2d1d418eSSumit Saxena 		"create reply queue timeout"
1290*2d1d418eSSumit Saxena 	},
1291*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" },
1292*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" },
1293*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" },
1294*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" },
1295*2d1d418eSSumit Saxena 	{
1296*2d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_CIACTVRST_TIMER,
1297*2d1d418eSSumit Saxena 		"component image activation timeout"
1298*2d1d418eSSumit Saxena 	},
1299*2d1d418eSSumit Saxena 	{
1300*2d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT,
1301*2d1d418eSSumit Saxena 		"get package version timeout"
1302*2d1d418eSSumit Saxena 	},
1303*2d1d418eSSumit Saxena 	{
1304*2d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_PELABORT_TIMEOUT,
1305*2d1d418eSSumit Saxena 		"persistent event log abort timeout"
1306*2d1d418eSSumit Saxena 	},
1307*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
1308*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
1309*2d1d418eSSumit Saxena 	{
1310*2d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT,
1311*2d1d418eSSumit Saxena 		"diagnostic buffer post timeout"
1312*2d1d418eSSumit Saxena 	},
1313*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronus reset" },
1314*2d1d418eSSumit Saxena 	{ MPI3MR_RESET_REASON_COUNT, "Reset reason count" },
1315*2d1d418eSSumit Saxena };
1316*2d1d418eSSumit Saxena 
1317*2d1d418eSSumit Saxena /**
1318*2d1d418eSSumit Saxena  * mpi3mr_reset_rc_name - get reset reason code name
1319*2d1d418eSSumit Saxena  * @reason_code: reset reason code value
1320*2d1d418eSSumit Saxena  *
1321*2d1d418eSSumit Saxena  * Map reset reason to an NULL terminated ASCII string
1322*2d1d418eSSumit Saxena  *
1323*2d1d418eSSumit Saxena  * Return: Name corresponding to reset reason value or NULL.
1324*2d1d418eSSumit Saxena  */
1325*2d1d418eSSumit Saxena static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code)
1326*2d1d418eSSumit Saxena {
1327*2d1d418eSSumit Saxena 	int i;
1328*2d1d418eSSumit Saxena 	char *name = NULL;
1329*2d1d418eSSumit Saxena 
1330*2d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_RESET_REASON_COUNT; i++) {
1331*2d1d418eSSumit Saxena 		if (mpi3mr_reset_reason_codes[i].value == reason_code) {
1332*2d1d418eSSumit Saxena 			name = mpi3mr_reset_reason_codes[i].name;
1333*2d1d418eSSumit Saxena 			break;
1334*2d1d418eSSumit Saxena 		}
1335*2d1d418eSSumit Saxena 	}
1336*2d1d418eSSumit Saxena 	return name;
1337*2d1d418eSSumit Saxena }
1338*2d1d418eSSumit Saxena 
1339*2d1d418eSSumit Saxena #define MAX_RESET_TYPE 3
1340*2d1d418eSSumit Saxena /* Reset type to name mapper structure*/
1341*2d1d418eSSumit Saxena static const struct {
1342*2d1d418eSSumit Saxena 	U16 reset_type;
1343*2d1d418eSSumit Saxena 	char *name;
1344*2d1d418eSSumit Saxena } mpi3mr_reset_types[] = {
1345*2d1d418eSSumit Saxena 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" },
1346*2d1d418eSSumit Saxena 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" },
1347*2d1d418eSSumit Saxena 	{ MAX_RESET_TYPE, "count"}
1348*2d1d418eSSumit Saxena };
1349*2d1d418eSSumit Saxena 
1350*2d1d418eSSumit Saxena /**
1351*2d1d418eSSumit Saxena  * mpi3mr_reset_type_name - get reset type name
1352*2d1d418eSSumit Saxena  * @reset_type: reset type value
1353*2d1d418eSSumit Saxena  *
1354*2d1d418eSSumit Saxena  * Map reset type to an NULL terminated ASCII string
1355*2d1d418eSSumit Saxena  *
1356*2d1d418eSSumit Saxena  * Return: Name corresponding to reset type value or NULL.
1357*2d1d418eSSumit Saxena  */
1358*2d1d418eSSumit Saxena static const char *mpi3mr_reset_type_name(U16 reset_type)
1359*2d1d418eSSumit Saxena {
1360*2d1d418eSSumit Saxena 	int i;
1361*2d1d418eSSumit Saxena 	char *name = NULL;
1362*2d1d418eSSumit Saxena 
1363*2d1d418eSSumit Saxena 	for (i = 0; i < MAX_RESET_TYPE; i++) {
1364*2d1d418eSSumit Saxena 		if (mpi3mr_reset_types[i].reset_type == reset_type) {
1365*2d1d418eSSumit Saxena 			name = mpi3mr_reset_types[i].name;
1366*2d1d418eSSumit Saxena 			break;
1367*2d1d418eSSumit Saxena 		}
1368*2d1d418eSSumit Saxena 	}
1369*2d1d418eSSumit Saxena 	return name;
1370*2d1d418eSSumit Saxena }
1371*2d1d418eSSumit Saxena 
1372*2d1d418eSSumit Saxena /**
1373*2d1d418eSSumit Saxena  * mpi3mr_soft_reset_success - Check softreset is success or not
1374*2d1d418eSSumit Saxena  * @ioc_status: IOC status register value
1375*2d1d418eSSumit Saxena  * @ioc_config: IOC config register value
1376*2d1d418eSSumit Saxena  *
1377*2d1d418eSSumit Saxena  * Check whether the soft reset is successful or not based on
1378*2d1d418eSSumit Saxena  * IOC status and IOC config register values.
1379*2d1d418eSSumit Saxena  *
1380*2d1d418eSSumit Saxena  * Return: True when the soft reset is success, false otherwise.
1381*2d1d418eSSumit Saxena  */
1382*2d1d418eSSumit Saxena static inline bool
1383*2d1d418eSSumit Saxena mpi3mr_soft_reset_success(U32 ioc_status, U32 ioc_config)
1384*2d1d418eSSumit Saxena {
1385*2d1d418eSSumit Saxena 	if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
1386*2d1d418eSSumit Saxena 	    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
1387*2d1d418eSSumit Saxena 	    (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
1388*2d1d418eSSumit Saxena 		return true;
1389*2d1d418eSSumit Saxena 	return false;
1390*2d1d418eSSumit Saxena }
1391*2d1d418eSSumit Saxena 
1392*2d1d418eSSumit Saxena /**
1393*2d1d418eSSumit Saxena  * mpi3mr_diagfault_success - Check diag fault is success or not
1394*2d1d418eSSumit Saxena  * @sc: Adapter reference
1395*2d1d418eSSumit Saxena  * @ioc_status: IOC status register value
1396*2d1d418eSSumit Saxena  *
1397*2d1d418eSSumit Saxena  * Check whether the controller hit diag reset fault code.
1398*2d1d418eSSumit Saxena  *
1399*2d1d418eSSumit Saxena  * Return: True when there is diag fault, false otherwise.
1400*2d1d418eSSumit Saxena  */
1401*2d1d418eSSumit Saxena static inline bool mpi3mr_diagfault_success(struct mpi3mr_softc *sc,
1402*2d1d418eSSumit Saxena 	U32 ioc_status)
1403*2d1d418eSSumit Saxena {
1404*2d1d418eSSumit Saxena 	U32 fault;
1405*2d1d418eSSumit Saxena 
1406*2d1d418eSSumit Saxena 	if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT))
1407*2d1d418eSSumit Saxena 		return false;
1408*2d1d418eSSumit Saxena 	fault = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_OFFSET) & MPI3_SYSIF_FAULT_CODE_MASK;
1409*2d1d418eSSumit Saxena 	if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET)
1410*2d1d418eSSumit Saxena 		return true;
1411*2d1d418eSSumit Saxena 	return false;
1412*2d1d418eSSumit Saxena }
1413*2d1d418eSSumit Saxena 
1414*2d1d418eSSumit Saxena /**
1415*2d1d418eSSumit Saxena  * mpi3mr_issue_iocfacts - Send IOC Facts
1416*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
1417*2d1d418eSSumit Saxena  * @facts_data: Cached IOC facts data
1418*2d1d418eSSumit Saxena  *
1419*2d1d418eSSumit Saxena  * Issue IOC Facts MPI request through admin queue and wait for
1420*2d1d418eSSumit Saxena  * the completion of it or time out.
1421*2d1d418eSSumit Saxena  *
1422*2d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failures.
1423*2d1d418eSSumit Saxena  */
1424*2d1d418eSSumit Saxena static int mpi3mr_issue_iocfacts(struct mpi3mr_softc *sc,
1425*2d1d418eSSumit Saxena     Mpi3IOCFactsData_t *facts_data)
1426*2d1d418eSSumit Saxena {
1427*2d1d418eSSumit Saxena 	Mpi3IOCFactsRequest_t iocfacts_req;
1428*2d1d418eSSumit Saxena 	bus_dma_tag_t data_tag = NULL;
1429*2d1d418eSSumit Saxena 	bus_dmamap_t data_map = NULL;
1430*2d1d418eSSumit Saxena 	bus_addr_t data_phys = 0;
1431*2d1d418eSSumit Saxena 	void *data = NULL;
1432*2d1d418eSSumit Saxena 	U32 data_len = sizeof(*facts_data);
1433*2d1d418eSSumit Saxena 	int retval = 0;
1434*2d1d418eSSumit Saxena 
1435*2d1d418eSSumit Saxena 	U8 sgl_flags = (MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE |
1436*2d1d418eSSumit Saxena                 	MPI3_SGE_FLAGS_DLAS_SYSTEM |
1437*2d1d418eSSumit Saxena 			MPI3_SGE_FLAGS_END_OF_LIST);
1438*2d1d418eSSumit Saxena 
1439*2d1d418eSSumit Saxena 
1440*2d1d418eSSumit Saxena         if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
1441*2d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
1442*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
1443*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
1444*2d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
1445*2d1d418eSSumit Saxena                                 data_len,		/* maxsize */
1446*2d1d418eSSumit Saxena                                 1,			/* nsegments */
1447*2d1d418eSSumit Saxena                                 data_len,		/* maxsegsize */
1448*2d1d418eSSumit Saxena                                 0,			/* flags */
1449*2d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
1450*2d1d418eSSumit Saxena                                 &data_tag)) {
1451*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
1452*2d1d418eSSumit Saxena 		return (ENOMEM);
1453*2d1d418eSSumit Saxena         }
1454*2d1d418eSSumit Saxena 
1455*2d1d418eSSumit Saxena         if (bus_dmamem_alloc(data_tag, (void **)&data,
1456*2d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &data_map)) {
1457*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d Data  DMA mem alloc failed\n",
1458*2d1d418eSSumit Saxena 			__func__, __LINE__);
1459*2d1d418eSSumit Saxena 		return (ENOMEM);
1460*2d1d418eSSumit Saxena         }
1461*2d1d418eSSumit Saxena 
1462*2d1d418eSSumit Saxena         bzero(data, data_len);
1463*2d1d418eSSumit Saxena         bus_dmamap_load(data_tag, data_map, data, data_len,
1464*2d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &data_phys, 0);
1465*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d IOCfacts data phys addr= %#016jx size= %d\n",
1466*2d1d418eSSumit Saxena 	    __func__, __LINE__, (uintmax_t)data_phys, data_len);
1467*2d1d418eSSumit Saxena 
1468*2d1d418eSSumit Saxena 	if (!data)
1469*2d1d418eSSumit Saxena 	{
1470*2d1d418eSSumit Saxena 		retval = -1;
1471*2d1d418eSSumit Saxena 		printf(IOCNAME "Memory alloc for IOCFactsData: failed\n",
1472*2d1d418eSSumit Saxena 		    sc->name);
1473*2d1d418eSSumit Saxena 		goto out;
1474*2d1d418eSSumit Saxena 	}
1475*2d1d418eSSumit Saxena 
1476*2d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
1477*2d1d418eSSumit Saxena 	memset(&iocfacts_req, 0, sizeof(iocfacts_req));
1478*2d1d418eSSumit Saxena 
1479*2d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
1480*2d1d418eSSumit Saxena 		retval = -1;
1481*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCFacts: Init command is in use\n",
1482*2d1d418eSSumit Saxena 		    sc->name);
1483*2d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
1484*2d1d418eSSumit Saxena 		goto out;
1485*2d1d418eSSumit Saxena 	}
1486*2d1d418eSSumit Saxena 
1487*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
1488*2d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
1489*2d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
1490*2d1d418eSSumit Saxena 	iocfacts_req.HostTag = (MPI3MR_HOSTTAG_INITCMDS);
1491*2d1d418eSSumit Saxena 	iocfacts_req.Function = MPI3_FUNCTION_IOC_FACTS;
1492*2d1d418eSSumit Saxena 
1493*2d1d418eSSumit Saxena 	mpi3mr_add_sg_single(&iocfacts_req.SGL, sgl_flags, data_len,
1494*2d1d418eSSumit Saxena 	    data_phys);
1495*2d1d418eSSumit Saxena 
1496*2d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
1497*2d1d418eSSumit Saxena 
1498*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &iocfacts_req,
1499*2d1d418eSSumit Saxena 	    sizeof(iocfacts_req));
1500*2d1d418eSSumit Saxena 
1501*2d1d418eSSumit Saxena 	if (retval) {
1502*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCFacts: Admin Post failed\n",
1503*2d1d418eSSumit Saxena 		    sc->name);
1504*2d1d418eSSumit Saxena 		goto out_unlock;
1505*2d1d418eSSumit Saxena 	}
1506*2d1d418eSSumit Saxena 
1507*2d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
1508*2d1d418eSSumit Saxena 	    (MPI3MR_INTADMCMD_TIMEOUT));
1509*2d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
1510*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCFacts: command timed out\n",
1511*2d1d418eSSumit Saxena 		    sc->name);
1512*2d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
1513*2d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT);
1514*2d1d418eSSumit Saxena 		sc->unrecoverable = 1;
1515*2d1d418eSSumit Saxena 		retval = -1;
1516*2d1d418eSSumit Saxena 		goto out_unlock;
1517*2d1d418eSSumit Saxena 	}
1518*2d1d418eSSumit Saxena 
1519*2d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
1520*2d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
1521*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCFacts: Failed IOCStatus(0x%04x) "
1522*2d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
1523*2d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
1524*2d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
1525*2d1d418eSSumit Saxena 		retval = -1;
1526*2d1d418eSSumit Saxena 		goto out_unlock;
1527*2d1d418eSSumit Saxena 	}
1528*2d1d418eSSumit Saxena 
1529*2d1d418eSSumit Saxena 	memcpy(facts_data, (U8 *)data, data_len);
1530*2d1d418eSSumit Saxena out_unlock:
1531*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
1532*2d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
1533*2d1d418eSSumit Saxena 
1534*2d1d418eSSumit Saxena out:
1535*2d1d418eSSumit Saxena 	if (data_phys != 0)
1536*2d1d418eSSumit Saxena 		bus_dmamap_unload(data_tag, data_map);
1537*2d1d418eSSumit Saxena 	if (data != NULL)
1538*2d1d418eSSumit Saxena 		bus_dmamem_free(data_tag, data, data_map);
1539*2d1d418eSSumit Saxena 	if (data_tag != NULL)
1540*2d1d418eSSumit Saxena 		bus_dma_tag_destroy(data_tag);
1541*2d1d418eSSumit Saxena 	return retval;
1542*2d1d418eSSumit Saxena }
1543*2d1d418eSSumit Saxena 
1544*2d1d418eSSumit Saxena /**
1545*2d1d418eSSumit Saxena  * mpi3mr_process_factsdata - Process IOC facts data
1546*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
1547*2d1d418eSSumit Saxena  * @facts_data: Cached IOC facts data
1548*2d1d418eSSumit Saxena  *
1549*2d1d418eSSumit Saxena  * Convert IOC facts data into cpu endianness and cache it in
1550*2d1d418eSSumit Saxena  * the driver .
1551*2d1d418eSSumit Saxena  *
1552*2d1d418eSSumit Saxena  * Return: Nothing.
1553*2d1d418eSSumit Saxena  */
1554*2d1d418eSSumit Saxena static int mpi3mr_process_factsdata(struct mpi3mr_softc *sc,
1555*2d1d418eSSumit Saxena     Mpi3IOCFactsData_t *facts_data)
1556*2d1d418eSSumit Saxena {
1557*2d1d418eSSumit Saxena 	int retval = 0;
1558*2d1d418eSSumit Saxena 	U32 ioc_config, req_sz, facts_flags;
1559*2d1d418eSSumit Saxena 
1560*2d1d418eSSumit Saxena 	if (le16toh(facts_data->IOCFactsDataLength) !=
1561*2d1d418eSSumit Saxena 	    (sizeof(*facts_data) / 4)) {
1562*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "IOCFacts data length mismatch "
1563*2d1d418eSSumit Saxena 		    " driver_sz(%ld) firmware_sz(%d) \n",
1564*2d1d418eSSumit Saxena 		    sizeof(*facts_data),
1565*2d1d418eSSumit Saxena 		    facts_data->IOCFactsDataLength);
1566*2d1d418eSSumit Saxena 	}
1567*2d1d418eSSumit Saxena 
1568*2d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
1569*2d1d418eSSumit Saxena         req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >>
1570*2d1d418eSSumit Saxena                   MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT);
1571*2d1d418eSSumit Saxena 
1572*2d1d418eSSumit Saxena 	if (facts_data->IOCRequestFrameSize != (req_sz/4)) {
1573*2d1d418eSSumit Saxena 		 mpi3mr_dprint(sc, MPI3MR_INFO, "IOCFacts data reqFrameSize mismatch "
1574*2d1d418eSSumit Saxena 		    " hw_size(%d) firmware_sz(%d) \n" , req_sz/4,
1575*2d1d418eSSumit Saxena 		    facts_data->IOCRequestFrameSize);
1576*2d1d418eSSumit Saxena 	}
1577*2d1d418eSSumit Saxena 
1578*2d1d418eSSumit Saxena 	memset(&sc->facts, 0, sizeof(sc->facts));
1579*2d1d418eSSumit Saxena 
1580*2d1d418eSSumit Saxena 	facts_flags = le32toh(facts_data->Flags);
1581*2d1d418eSSumit Saxena 	sc->facts.op_req_sz = req_sz;
1582*2d1d418eSSumit Saxena 	sc->op_reply_sz = 1 << ((ioc_config &
1583*2d1d418eSSumit Saxena                                   MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >>
1584*2d1d418eSSumit Saxena                                   MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT);
1585*2d1d418eSSumit Saxena 
1586*2d1d418eSSumit Saxena 	sc->facts.ioc_num = facts_data->IOCNumber;
1587*2d1d418eSSumit Saxena         sc->facts.who_init = facts_data->WhoInit;
1588*2d1d418eSSumit Saxena         sc->facts.max_msix_vectors = facts_data->MaxMSIxVectors;
1589*2d1d418eSSumit Saxena 	sc->facts.personality = (facts_flags &
1590*2d1d418eSSumit Saxena 	    MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK);
1591*2d1d418eSSumit Saxena 	sc->facts.dma_mask = (facts_flags &
1592*2d1d418eSSumit Saxena 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
1593*2d1d418eSSumit Saxena 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
1594*2d1d418eSSumit Saxena         sc->facts.protocol_flags = facts_data->ProtocolFlags;
1595*2d1d418eSSumit Saxena         sc->facts.mpi_version = (facts_data->MPIVersion.Word);
1596*2d1d418eSSumit Saxena         sc->facts.max_reqs = (facts_data->MaxOutstandingRequests);
1597*2d1d418eSSumit Saxena         sc->facts.product_id = (facts_data->ProductID);
1598*2d1d418eSSumit Saxena 	sc->facts.reply_sz = (facts_data->ReplyFrameSize) * 4;
1599*2d1d418eSSumit Saxena         sc->facts.exceptions = (facts_data->IOCExceptions);
1600*2d1d418eSSumit Saxena         sc->facts.max_perids = (facts_data->MaxPersistentID);
1601*2d1d418eSSumit Saxena         sc->facts.max_vds = (facts_data->MaxVDs);
1602*2d1d418eSSumit Saxena         sc->facts.max_hpds = (facts_data->MaxHostPDs);
1603*2d1d418eSSumit Saxena         sc->facts.max_advhpds = (facts_data->MaxAdvHostPDs);
1604*2d1d418eSSumit Saxena         sc->facts.max_raidpds = (facts_data->MaxRAIDPDs);
1605*2d1d418eSSumit Saxena         sc->facts.max_nvme = (facts_data->MaxNVMe);
1606*2d1d418eSSumit Saxena         sc->facts.max_pcieswitches =
1607*2d1d418eSSumit Saxena                 (facts_data->MaxPCIeSwitches);
1608*2d1d418eSSumit Saxena         sc->facts.max_sasexpanders =
1609*2d1d418eSSumit Saxena                 (facts_data->MaxSASExpanders);
1610*2d1d418eSSumit Saxena         sc->facts.max_sasinitiators =
1611*2d1d418eSSumit Saxena                 (facts_data->MaxSASInitiators);
1612*2d1d418eSSumit Saxena         sc->facts.max_enclosures = (facts_data->MaxEnclosures);
1613*2d1d418eSSumit Saxena         sc->facts.min_devhandle = (facts_data->MinDevHandle);
1614*2d1d418eSSumit Saxena         sc->facts.max_devhandle = (facts_data->MaxDevHandle);
1615*2d1d418eSSumit Saxena 	sc->facts.max_op_req_q =
1616*2d1d418eSSumit Saxena                 (facts_data->MaxOperationalRequestQueues);
1617*2d1d418eSSumit Saxena 	sc->facts.max_op_reply_q =
1618*2d1d418eSSumit Saxena                 (facts_data->MaxOperationalReplyQueues);
1619*2d1d418eSSumit Saxena         sc->facts.ioc_capabilities =
1620*2d1d418eSSumit Saxena                 (facts_data->IOCCapabilities);
1621*2d1d418eSSumit Saxena         sc->facts.fw_ver.build_num =
1622*2d1d418eSSumit Saxena                 (facts_data->FWVersion.BuildNum);
1623*2d1d418eSSumit Saxena         sc->facts.fw_ver.cust_id =
1624*2d1d418eSSumit Saxena                 (facts_data->FWVersion.CustomerID);
1625*2d1d418eSSumit Saxena         sc->facts.fw_ver.ph_minor = facts_data->FWVersion.PhaseMinor;
1626*2d1d418eSSumit Saxena         sc->facts.fw_ver.ph_major = facts_data->FWVersion.PhaseMajor;
1627*2d1d418eSSumit Saxena         sc->facts.fw_ver.gen_minor = facts_data->FWVersion.GenMinor;
1628*2d1d418eSSumit Saxena         sc->facts.fw_ver.gen_major = facts_data->FWVersion.GenMajor;
1629*2d1d418eSSumit Saxena         sc->max_msix_vectors = min(sc->max_msix_vectors,
1630*2d1d418eSSumit Saxena             sc->facts.max_msix_vectors);
1631*2d1d418eSSumit Saxena         sc->facts.sge_mod_mask = facts_data->SGEModifierMask;
1632*2d1d418eSSumit Saxena         sc->facts.sge_mod_value = facts_data->SGEModifierValue;
1633*2d1d418eSSumit Saxena         sc->facts.sge_mod_shift = facts_data->SGEModifierShift;
1634*2d1d418eSSumit Saxena         sc->facts.shutdown_timeout =
1635*2d1d418eSSumit Saxena                 (facts_data->ShutdownTimeout);
1636*2d1d418eSSumit Saxena 	sc->facts.max_dev_per_tg = facts_data->MaxDevicesPerThrottleGroup;
1637*2d1d418eSSumit Saxena 	sc->facts.io_throttle_data_length =
1638*2d1d418eSSumit Saxena 	    facts_data->IOThrottleDataLength;
1639*2d1d418eSSumit Saxena 	sc->facts.max_io_throttle_group =
1640*2d1d418eSSumit Saxena 	    facts_data->MaxIOThrottleGroup;
1641*2d1d418eSSumit Saxena 	sc->facts.io_throttle_low = facts_data->IOThrottleLow;
1642*2d1d418eSSumit Saxena 	sc->facts.io_throttle_high = facts_data->IOThrottleHigh;
1643*2d1d418eSSumit Saxena 
1644*2d1d418eSSumit Saxena 	/*Store in 512b block count*/
1645*2d1d418eSSumit Saxena 	if (sc->facts.io_throttle_data_length)
1646*2d1d418eSSumit Saxena 		sc->io_throttle_data_length =
1647*2d1d418eSSumit Saxena 		    (sc->facts.io_throttle_data_length * 2 * 4);
1648*2d1d418eSSumit Saxena 	else
1649*2d1d418eSSumit Saxena 		/* set the length to 1MB + 1K to disable throttle*/
1650*2d1d418eSSumit Saxena 		sc->io_throttle_data_length = MPI3MR_MAX_SECTORS + 2;
1651*2d1d418eSSumit Saxena 
1652*2d1d418eSSumit Saxena 	sc->io_throttle_high = (sc->facts.io_throttle_high * 2 * 1024);
1653*2d1d418eSSumit Saxena 	sc->io_throttle_low = (sc->facts.io_throttle_low * 2 * 1024);
1654*2d1d418eSSumit Saxena 
1655*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),"
1656*2d1d418eSSumit Saxena             "maxreqs(%d), mindh(%d) maxPDs(%d) maxvectors(%d) maxperids(%d)\n",
1657*2d1d418eSSumit Saxena 	    sc->facts.ioc_num, sc->facts.max_op_req_q,
1658*2d1d418eSSumit Saxena 	    sc->facts.max_op_reply_q, sc->facts.max_devhandle,
1659*2d1d418eSSumit Saxena             sc->facts.max_reqs, sc->facts.min_devhandle,
1660*2d1d418eSSumit Saxena             sc->facts.max_pds, sc->facts.max_msix_vectors,
1661*2d1d418eSSumit Saxena             sc->facts.max_perids);
1662*2d1d418eSSumit Saxena         mpi3mr_dprint(sc, MPI3MR_INFO, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x\n",
1663*2d1d418eSSumit Saxena             sc->facts.sge_mod_mask, sc->facts.sge_mod_value,
1664*2d1d418eSSumit Saxena             sc->facts.sge_mod_shift);
1665*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
1666*2d1d418eSSumit Saxena 	    "max_dev_per_throttle_group(%d), max_throttle_groups(%d), io_throttle_data_len(%dKiB), io_throttle_high(%dMiB), io_throttle_low(%dMiB)\n",
1667*2d1d418eSSumit Saxena 	    sc->facts.max_dev_per_tg, sc->facts.max_io_throttle_group,
1668*2d1d418eSSumit Saxena 	    sc->facts.io_throttle_data_length * 4,
1669*2d1d418eSSumit Saxena 	    sc->facts.io_throttle_high, sc->facts.io_throttle_low);
1670*2d1d418eSSumit Saxena 
1671*2d1d418eSSumit Saxena 	sc->max_host_ios = sc->facts.max_reqs -
1672*2d1d418eSSumit Saxena 	    (MPI3MR_INTERNALCMDS_RESVD + 1);
1673*2d1d418eSSumit Saxena 
1674*2d1d418eSSumit Saxena 	return retval;
1675*2d1d418eSSumit Saxena }
1676*2d1d418eSSumit Saxena 
1677*2d1d418eSSumit Saxena static inline void mpi3mr_setup_reply_free_queues(struct mpi3mr_softc *sc)
1678*2d1d418eSSumit Saxena {
1679*2d1d418eSSumit Saxena 	int i;
1680*2d1d418eSSumit Saxena 	bus_addr_t phys_addr;
1681*2d1d418eSSumit Saxena 
1682*2d1d418eSSumit Saxena 	/* initialize Reply buffer Queue */
1683*2d1d418eSSumit Saxena 	for (i = 0, phys_addr = sc->reply_buf_phys;
1684*2d1d418eSSumit Saxena 	    i < sc->num_reply_bufs; i++, phys_addr += sc->reply_sz)
1685*2d1d418eSSumit Saxena 		sc->reply_free_q[i] = phys_addr;
1686*2d1d418eSSumit Saxena 	sc->reply_free_q[i] = (0);
1687*2d1d418eSSumit Saxena 
1688*2d1d418eSSumit Saxena 	/* initialize Sense Buffer Queue */
1689*2d1d418eSSumit Saxena 	for (i = 0, phys_addr = sc->sense_buf_phys;
1690*2d1d418eSSumit Saxena 	    i < sc->num_sense_bufs; i++, phys_addr += MPI3MR_SENSEBUF_SZ)
1691*2d1d418eSSumit Saxena 		sc->sense_buf_q[i] = phys_addr;
1692*2d1d418eSSumit Saxena 	sc->sense_buf_q[i] = (0);
1693*2d1d418eSSumit Saxena 
1694*2d1d418eSSumit Saxena }
1695*2d1d418eSSumit Saxena 
1696*2d1d418eSSumit Saxena static int mpi3mr_reply_dma_alloc(struct mpi3mr_softc *sc)
1697*2d1d418eSSumit Saxena {
1698*2d1d418eSSumit Saxena 	U32 sz;
1699*2d1d418eSSumit Saxena 
1700*2d1d418eSSumit Saxena 	sc->num_reply_bufs = sc->facts.max_reqs + MPI3MR_NUM_EVTREPLIES;
1701*2d1d418eSSumit Saxena 	sc->reply_free_q_sz = sc->num_reply_bufs + 1;
1702*2d1d418eSSumit Saxena 	sc->num_sense_bufs = sc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
1703*2d1d418eSSumit Saxena 	sc->sense_buf_q_sz = sc->num_sense_bufs + 1;
1704*2d1d418eSSumit Saxena 
1705*2d1d418eSSumit Saxena 	sz = sc->num_reply_bufs * sc->reply_sz;
1706*2d1d418eSSumit Saxena 
1707*2d1d418eSSumit Saxena 	if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,  /* parent */
1708*2d1d418eSSumit Saxena 				16, 0,			/* algnmnt, boundary */
1709*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
1710*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
1711*2d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
1712*2d1d418eSSumit Saxena                                 sz,			/* maxsize */
1713*2d1d418eSSumit Saxena                                 1,			/* nsegments */
1714*2d1d418eSSumit Saxena                                 sz,			/* maxsegsize */
1715*2d1d418eSSumit Saxena                                 0,			/* flags */
1716*2d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
1717*2d1d418eSSumit Saxena                                 &sc->reply_buf_tag)) {
1718*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
1719*2d1d418eSSumit Saxena 		return (ENOMEM);
1720*2d1d418eSSumit Saxena         }
1721*2d1d418eSSumit Saxena 
1722*2d1d418eSSumit Saxena 	if (bus_dmamem_alloc(sc->reply_buf_tag, (void **)&sc->reply_buf,
1723*2d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &sc->reply_buf_dmamap)) {
1724*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d  DMA mem alloc failed\n",
1725*2d1d418eSSumit Saxena 			__func__, __LINE__);
1726*2d1d418eSSumit Saxena 		return (ENOMEM);
1727*2d1d418eSSumit Saxena         }
1728*2d1d418eSSumit Saxena 
1729*2d1d418eSSumit Saxena 	bzero(sc->reply_buf, sz);
1730*2d1d418eSSumit Saxena         bus_dmamap_load(sc->reply_buf_tag, sc->reply_buf_dmamap, sc->reply_buf, sz,
1731*2d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &sc->reply_buf_phys, 0);
1732*2d1d418eSSumit Saxena 
1733*2d1d418eSSumit Saxena 	sc->reply_buf_dma_min_address = sc->reply_buf_phys;
1734*2d1d418eSSumit Saxena 	sc->reply_buf_dma_max_address = sc->reply_buf_phys + sz;
1735*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "reply buf (0x%p): depth(%d), frame_size(%d), "
1736*2d1d418eSSumit Saxena 	    "pool_size(%d kB), reply_buf_dma(0x%llx)\n",
1737*2d1d418eSSumit Saxena 	    sc->reply_buf, sc->num_reply_bufs, sc->reply_sz,
1738*2d1d418eSSumit Saxena 	    (sz / 1024), (unsigned long long)sc->reply_buf_phys);
1739*2d1d418eSSumit Saxena 
1740*2d1d418eSSumit Saxena 	/* reply free queue, 8 byte align */
1741*2d1d418eSSumit Saxena 	sz = sc->reply_free_q_sz * 8;
1742*2d1d418eSSumit Saxena 
1743*2d1d418eSSumit Saxena         if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
1744*2d1d418eSSumit Saxena 				8, 0,			/* algnmnt, boundary */
1745*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
1746*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
1747*2d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
1748*2d1d418eSSumit Saxena                                 sz,			/* maxsize */
1749*2d1d418eSSumit Saxena                                 1,			/* nsegments */
1750*2d1d418eSSumit Saxena                                 sz,			/* maxsegsize */
1751*2d1d418eSSumit Saxena                                 0,			/* flags */
1752*2d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
1753*2d1d418eSSumit Saxena                                 &sc->reply_free_q_tag)) {
1754*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate reply free queue DMA tag\n");
1755*2d1d418eSSumit Saxena 		return (ENOMEM);
1756*2d1d418eSSumit Saxena         }
1757*2d1d418eSSumit Saxena 
1758*2d1d418eSSumit Saxena         if (bus_dmamem_alloc(sc->reply_free_q_tag, (void **)&sc->reply_free_q,
1759*2d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &sc->reply_free_q_dmamap)) {
1760*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d  DMA mem alloc failed\n",
1761*2d1d418eSSumit Saxena 			__func__, __LINE__);
1762*2d1d418eSSumit Saxena 		return (ENOMEM);
1763*2d1d418eSSumit Saxena         }
1764*2d1d418eSSumit Saxena 
1765*2d1d418eSSumit Saxena 	bzero(sc->reply_free_q, sz);
1766*2d1d418eSSumit Saxena         bus_dmamap_load(sc->reply_free_q_tag, sc->reply_free_q_dmamap, sc->reply_free_q, sz,
1767*2d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &sc->reply_free_q_phys, 0);
1768*2d1d418eSSumit Saxena 
1769*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "reply_free_q (0x%p): depth(%d), frame_size(%d), "
1770*2d1d418eSSumit Saxena 	    "pool_size(%d kB), reply_free_q_dma(0x%llx)\n",
1771*2d1d418eSSumit Saxena 	    sc->reply_free_q, sc->reply_free_q_sz, 8, (sz / 1024),
1772*2d1d418eSSumit Saxena 	    (unsigned long long)sc->reply_free_q_phys);
1773*2d1d418eSSumit Saxena 
1774*2d1d418eSSumit Saxena 	/* sense buffer pool,  4 byte align */
1775*2d1d418eSSumit Saxena 	sz = sc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
1776*2d1d418eSSumit Saxena 
1777*2d1d418eSSumit Saxena         if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
1778*2d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
1779*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
1780*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
1781*2d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
1782*2d1d418eSSumit Saxena                                 sz,			/* maxsize */
1783*2d1d418eSSumit Saxena                                 1,			/* nsegments */
1784*2d1d418eSSumit Saxena                                 sz,			/* maxsegsize */
1785*2d1d418eSSumit Saxena                                 0,			/* flags */
1786*2d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
1787*2d1d418eSSumit Saxena                                 &sc->sense_buf_tag)) {
1788*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Sense buffer DMA tag\n");
1789*2d1d418eSSumit Saxena 		return (ENOMEM);
1790*2d1d418eSSumit Saxena         }
1791*2d1d418eSSumit Saxena 
1792*2d1d418eSSumit Saxena 	if (bus_dmamem_alloc(sc->sense_buf_tag, (void **)&sc->sense_buf,
1793*2d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &sc->sense_buf_dmamap)) {
1794*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d  DMA mem alloc failed\n",
1795*2d1d418eSSumit Saxena 			__func__, __LINE__);
1796*2d1d418eSSumit Saxena 		return (ENOMEM);
1797*2d1d418eSSumit Saxena         }
1798*2d1d418eSSumit Saxena 
1799*2d1d418eSSumit Saxena 	bzero(sc->sense_buf, sz);
1800*2d1d418eSSumit Saxena         bus_dmamap_load(sc->sense_buf_tag, sc->sense_buf_dmamap, sc->sense_buf, sz,
1801*2d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &sc->sense_buf_phys, 0);
1802*2d1d418eSSumit Saxena 
1803*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "sense_buf (0x%p): depth(%d), frame_size(%d), "
1804*2d1d418eSSumit Saxena 	    "pool_size(%d kB), sense_dma(0x%llx)\n",
1805*2d1d418eSSumit Saxena 	    sc->sense_buf, sc->num_sense_bufs, MPI3MR_SENSEBUF_SZ,
1806*2d1d418eSSumit Saxena 	    (sz / 1024), (unsigned long long)sc->sense_buf_phys);
1807*2d1d418eSSumit Saxena 
1808*2d1d418eSSumit Saxena 	/* sense buffer queue, 8 byte align */
1809*2d1d418eSSumit Saxena 	sz = sc->sense_buf_q_sz * 8;
1810*2d1d418eSSumit Saxena 
1811*2d1d418eSSumit Saxena         if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
1812*2d1d418eSSumit Saxena 				8, 0,			/* algnmnt, boundary */
1813*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
1814*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
1815*2d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
1816*2d1d418eSSumit Saxena                                 sz,			/* maxsize */
1817*2d1d418eSSumit Saxena                                 1,			/* nsegments */
1818*2d1d418eSSumit Saxena                                 sz,			/* maxsegsize */
1819*2d1d418eSSumit Saxena                                 0,			/* flags */
1820*2d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
1821*2d1d418eSSumit Saxena                                 &sc->sense_buf_q_tag)) {
1822*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Sense buffer Queue DMA tag\n");
1823*2d1d418eSSumit Saxena 		return (ENOMEM);
1824*2d1d418eSSumit Saxena         }
1825*2d1d418eSSumit Saxena 
1826*2d1d418eSSumit Saxena 	if (bus_dmamem_alloc(sc->sense_buf_q_tag, (void **)&sc->sense_buf_q,
1827*2d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &sc->sense_buf_q_dmamap)) {
1828*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d  DMA mem alloc failed\n",
1829*2d1d418eSSumit Saxena 			__func__, __LINE__);
1830*2d1d418eSSumit Saxena 		return (ENOMEM);
1831*2d1d418eSSumit Saxena         }
1832*2d1d418eSSumit Saxena 
1833*2d1d418eSSumit Saxena 	bzero(sc->sense_buf_q, sz);
1834*2d1d418eSSumit Saxena         bus_dmamap_load(sc->sense_buf_q_tag, sc->sense_buf_q_dmamap, sc->sense_buf_q, sz,
1835*2d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &sc->sense_buf_q_phys, 0);
1836*2d1d418eSSumit Saxena 
1837*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "sense_buf_q (0x%p): depth(%d), frame_size(%d), "
1838*2d1d418eSSumit Saxena 	    "pool_size(%d kB), sense_dma(0x%llx)\n",
1839*2d1d418eSSumit Saxena 	    sc->sense_buf_q, sc->sense_buf_q_sz, 8, (sz / 1024),
1840*2d1d418eSSumit Saxena 	    (unsigned long long)sc->sense_buf_q_phys);
1841*2d1d418eSSumit Saxena 
1842*2d1d418eSSumit Saxena 	return 0;
1843*2d1d418eSSumit Saxena }
1844*2d1d418eSSumit Saxena 
1845*2d1d418eSSumit Saxena static int mpi3mr_reply_alloc(struct mpi3mr_softc *sc)
1846*2d1d418eSSumit Saxena {
1847*2d1d418eSSumit Saxena 	int retval = 0;
1848*2d1d418eSSumit Saxena 	U32 i;
1849*2d1d418eSSumit Saxena 
1850*2d1d418eSSumit Saxena 	if (sc->init_cmds.reply)
1851*2d1d418eSSumit Saxena 		goto post_reply_sbuf;
1852*2d1d418eSSumit Saxena 
1853*2d1d418eSSumit Saxena 	sc->init_cmds.reply = malloc(sc->reply_sz,
1854*2d1d418eSSumit Saxena 		M_MPI3MR, M_NOWAIT | M_ZERO);
1855*2d1d418eSSumit Saxena 
1856*2d1d418eSSumit Saxena 	if (!sc->init_cmds.reply) {
1857*2d1d418eSSumit Saxena 		printf(IOCNAME "Cannot allocate memory for init_cmds.reply\n",
1858*2d1d418eSSumit Saxena 		    sc->name);
1859*2d1d418eSSumit Saxena 		goto out_failed;
1860*2d1d418eSSumit Saxena 	}
1861*2d1d418eSSumit Saxena 
1862*2d1d418eSSumit Saxena 	sc->ioctl_cmds.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO);
1863*2d1d418eSSumit Saxena 	if (!sc->ioctl_cmds.reply) {
1864*2d1d418eSSumit Saxena 		printf(IOCNAME "Cannot allocate memory for ioctl_cmds.reply\n",
1865*2d1d418eSSumit Saxena 		    sc->name);
1866*2d1d418eSSumit Saxena 		goto out_failed;
1867*2d1d418eSSumit Saxena 	}
1868*2d1d418eSSumit Saxena 
1869*2d1d418eSSumit Saxena 	sc->host_tm_cmds.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO);
1870*2d1d418eSSumit Saxena 	if (!sc->host_tm_cmds.reply) {
1871*2d1d418eSSumit Saxena 		printf(IOCNAME "Cannot allocate memory for host_tm.reply\n",
1872*2d1d418eSSumit Saxena 		    sc->name);
1873*2d1d418eSSumit Saxena 		goto out_failed;
1874*2d1d418eSSumit Saxena 	}
1875*2d1d418eSSumit Saxena 	for (i=0; i<MPI3MR_NUM_DEVRMCMD; i++) {
1876*2d1d418eSSumit Saxena 		sc->dev_rmhs_cmds[i].reply = malloc(sc->reply_sz,
1877*2d1d418eSSumit Saxena 		    M_MPI3MR, M_NOWAIT | M_ZERO);
1878*2d1d418eSSumit Saxena 		if (!sc->dev_rmhs_cmds[i].reply) {
1879*2d1d418eSSumit Saxena 			printf(IOCNAME "Cannot allocate memory for"
1880*2d1d418eSSumit Saxena 			    " dev_rmhs_cmd[%d].reply\n",
1881*2d1d418eSSumit Saxena 			    sc->name, i);
1882*2d1d418eSSumit Saxena 			goto out_failed;
1883*2d1d418eSSumit Saxena 		}
1884*2d1d418eSSumit Saxena 	}
1885*2d1d418eSSumit Saxena 
1886*2d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
1887*2d1d418eSSumit Saxena 		sc->evtack_cmds[i].reply = malloc(sc->reply_sz,
1888*2d1d418eSSumit Saxena 			M_MPI3MR, M_NOWAIT | M_ZERO);
1889*2d1d418eSSumit Saxena 		if (!sc->evtack_cmds[i].reply)
1890*2d1d418eSSumit Saxena 			goto out_failed;
1891*2d1d418eSSumit Saxena 	}
1892*2d1d418eSSumit Saxena 
1893*2d1d418eSSumit Saxena 	sc->dev_handle_bitmap_sz = MPI3MR_DIV_ROUND_UP(sc->facts.max_devhandle, 8);
1894*2d1d418eSSumit Saxena 
1895*2d1d418eSSumit Saxena 	sc->removepend_bitmap = malloc(sc->dev_handle_bitmap_sz,
1896*2d1d418eSSumit Saxena 	    M_MPI3MR, M_NOWAIT | M_ZERO);
1897*2d1d418eSSumit Saxena 	if (!sc->removepend_bitmap) {
1898*2d1d418eSSumit Saxena 		printf(IOCNAME "Cannot alloc memory for remove pend bitmap\n",
1899*2d1d418eSSumit Saxena 		    sc->name);
1900*2d1d418eSSumit Saxena 		goto out_failed;
1901*2d1d418eSSumit Saxena 	}
1902*2d1d418eSSumit Saxena 
1903*2d1d418eSSumit Saxena 	sc->devrem_bitmap_sz = MPI3MR_DIV_ROUND_UP(MPI3MR_NUM_DEVRMCMD, 8);
1904*2d1d418eSSumit Saxena 	sc->devrem_bitmap = malloc(sc->devrem_bitmap_sz,
1905*2d1d418eSSumit Saxena 	    M_MPI3MR, M_NOWAIT | M_ZERO);
1906*2d1d418eSSumit Saxena 	if (!sc->devrem_bitmap) {
1907*2d1d418eSSumit Saxena 		printf(IOCNAME "Cannot alloc memory for dev remove bitmap\n",
1908*2d1d418eSSumit Saxena 		    sc->name);
1909*2d1d418eSSumit Saxena 		goto out_failed;
1910*2d1d418eSSumit Saxena 	}
1911*2d1d418eSSumit Saxena 
1912*2d1d418eSSumit Saxena 	sc->evtack_cmds_bitmap_sz = MPI3MR_DIV_ROUND_UP(MPI3MR_NUM_EVTACKCMD, 8);
1913*2d1d418eSSumit Saxena 
1914*2d1d418eSSumit Saxena 	sc->evtack_cmds_bitmap = malloc(sc->evtack_cmds_bitmap_sz,
1915*2d1d418eSSumit Saxena 		M_MPI3MR, M_NOWAIT | M_ZERO);
1916*2d1d418eSSumit Saxena 	if (!sc->evtack_cmds_bitmap)
1917*2d1d418eSSumit Saxena 		goto out_failed;
1918*2d1d418eSSumit Saxena 
1919*2d1d418eSSumit Saxena 	if (mpi3mr_reply_dma_alloc(sc)) {
1920*2d1d418eSSumit Saxena 		printf(IOCNAME "func:%s line:%d DMA memory allocation failed\n",
1921*2d1d418eSSumit Saxena 		    sc->name, __func__, __LINE__);
1922*2d1d418eSSumit Saxena 		goto out_failed;
1923*2d1d418eSSumit Saxena 	}
1924*2d1d418eSSumit Saxena 
1925*2d1d418eSSumit Saxena post_reply_sbuf:
1926*2d1d418eSSumit Saxena 	mpi3mr_setup_reply_free_queues(sc);
1927*2d1d418eSSumit Saxena 	return retval;
1928*2d1d418eSSumit Saxena out_failed:
1929*2d1d418eSSumit Saxena 	mpi3mr_cleanup_interrupts(sc);
1930*2d1d418eSSumit Saxena 	mpi3mr_free_mem(sc);
1931*2d1d418eSSumit Saxena 	retval = -1;
1932*2d1d418eSSumit Saxena 	return retval;
1933*2d1d418eSSumit Saxena }
1934*2d1d418eSSumit Saxena 
1935*2d1d418eSSumit Saxena static void
1936*2d1d418eSSumit Saxena mpi3mr_print_fw_pkg_ver(struct mpi3mr_softc *sc)
1937*2d1d418eSSumit Saxena {
1938*2d1d418eSSumit Saxena 	int retval = 0;
1939*2d1d418eSSumit Saxena 	void *fw_pkg_ver = NULL;
1940*2d1d418eSSumit Saxena 	bus_dma_tag_t fw_pkg_ver_tag;
1941*2d1d418eSSumit Saxena 	bus_dmamap_t fw_pkg_ver_map;
1942*2d1d418eSSumit Saxena 	bus_addr_t fw_pkg_ver_dma;
1943*2d1d418eSSumit Saxena 	Mpi3CIUploadRequest_t ci_upload;
1944*2d1d418eSSumit Saxena 	Mpi3ComponentImageHeader_t *ci_header;
1945*2d1d418eSSumit Saxena 	U32 fw_pkg_ver_len = sizeof(*ci_header);
1946*2d1d418eSSumit Saxena 	U8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
1947*2d1d418eSSumit Saxena 
1948*2d1d418eSSumit Saxena 	if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,  /* parent */
1949*2d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
1950*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
1951*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
1952*2d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
1953*2d1d418eSSumit Saxena 				fw_pkg_ver_len,		/* maxsize */
1954*2d1d418eSSumit Saxena 				1,			/* nsegments */
1955*2d1d418eSSumit Saxena 				fw_pkg_ver_len,		/* maxsegsize */
1956*2d1d418eSSumit Saxena 				0,			/* flags */
1957*2d1d418eSSumit Saxena 				NULL, NULL,		/* lockfunc, lockarg */
1958*2d1d418eSSumit Saxena 				&fw_pkg_ver_tag)) {
1959*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate fw package version request DMA tag\n");
1960*2d1d418eSSumit Saxena 		return;
1961*2d1d418eSSumit Saxena 	}
1962*2d1d418eSSumit Saxena 
1963*2d1d418eSSumit Saxena 	if (bus_dmamem_alloc(fw_pkg_ver_tag, (void **)&fw_pkg_ver, BUS_DMA_NOWAIT, &fw_pkg_ver_map)) {
1964*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d fw package version DMA mem alloc failed\n",
1965*2d1d418eSSumit Saxena 			      __func__, __LINE__);
1966*2d1d418eSSumit Saxena 		return;
1967*2d1d418eSSumit Saxena 	}
1968*2d1d418eSSumit Saxena 
1969*2d1d418eSSumit Saxena 	bzero(fw_pkg_ver, fw_pkg_ver_len);
1970*2d1d418eSSumit Saxena 
1971*2d1d418eSSumit Saxena 	bus_dmamap_load(fw_pkg_ver_tag, fw_pkg_ver_map, fw_pkg_ver, fw_pkg_ver_len, mpi3mr_memaddr_cb, &fw_pkg_ver_dma, 0);
1972*2d1d418eSSumit Saxena 
1973*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d fw package version phys addr= %#016jx size= %d\n",
1974*2d1d418eSSumit Saxena 		      __func__, __LINE__, (uintmax_t)fw_pkg_ver_dma, fw_pkg_ver_len);
1975*2d1d418eSSumit Saxena 
1976*2d1d418eSSumit Saxena 	if (!fw_pkg_ver) {
1977*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Memory alloc for fw package version failed\n");
1978*2d1d418eSSumit Saxena 		goto out;
1979*2d1d418eSSumit Saxena 	}
1980*2d1d418eSSumit Saxena 
1981*2d1d418eSSumit Saxena 	memset(&ci_upload, 0, sizeof(ci_upload));
1982*2d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
1983*2d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
1984*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,"Issue CI Header Upload: command is in use\n");
1985*2d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
1986*2d1d418eSSumit Saxena 		goto out;
1987*2d1d418eSSumit Saxena 	}
1988*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
1989*2d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
1990*2d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
1991*2d1d418eSSumit Saxena 	ci_upload.HostTag = htole16(MPI3MR_HOSTTAG_INITCMDS);
1992*2d1d418eSSumit Saxena 	ci_upload.Function = MPI3_FUNCTION_CI_UPLOAD;
1993*2d1d418eSSumit Saxena 	ci_upload.MsgFlags = MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY;
1994*2d1d418eSSumit Saxena 	ci_upload.ImageOffset = MPI3_IMAGE_HEADER_SIGNATURE0_OFFSET;
1995*2d1d418eSSumit Saxena 	ci_upload.SegmentSize = MPI3_IMAGE_HEADER_SIZE;
1996*2d1d418eSSumit Saxena 
1997*2d1d418eSSumit Saxena 	mpi3mr_add_sg_single(&ci_upload.SGL, sgl_flags, fw_pkg_ver_len,
1998*2d1d418eSSumit Saxena 	    fw_pkg_ver_dma);
1999*2d1d418eSSumit Saxena 
2000*2d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
2001*2d1d418eSSumit Saxena 	if ((retval = mpi3mr_submit_admin_cmd(sc, &ci_upload, sizeof(ci_upload)))) {
2002*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Issue CI Header Upload: Admin Post failed\n");
2003*2d1d418eSSumit Saxena 		goto out_unlock;
2004*2d1d418eSSumit Saxena 	}
2005*2d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
2006*2d1d418eSSumit Saxena 		(MPI3MR_INTADMCMD_TIMEOUT));
2007*2d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2008*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Issue CI Header Upload: command timed out\n");
2009*2d1d418eSSumit Saxena 		sc->init_cmds.is_waiting = 0;
2010*2d1d418eSSumit Saxena 		if (!(sc->init_cmds.state & MPI3MR_CMD_RESET))
2011*2d1d418eSSumit Saxena 			mpi3mr_check_rh_fault_ioc(sc,
2012*2d1d418eSSumit Saxena 				MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT);
2013*2d1d418eSSumit Saxena 		goto out_unlock;
2014*2d1d418eSSumit Saxena 	}
2015*2d1d418eSSumit Saxena 	if ((GET_IOC_STATUS(sc->init_cmds.ioc_status)) != MPI3_IOCSTATUS_SUCCESS) {
2016*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
2017*2d1d418eSSumit Saxena 			      "Issue CI Header Upload: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n",
2018*2d1d418eSSumit Saxena 			      GET_IOC_STATUS(sc->init_cmds.ioc_status), sc->init_cmds.ioc_loginfo);
2019*2d1d418eSSumit Saxena 		goto out_unlock;
2020*2d1d418eSSumit Saxena 	}
2021*2d1d418eSSumit Saxena 
2022*2d1d418eSSumit Saxena 	ci_header = (Mpi3ComponentImageHeader_t *) fw_pkg_ver;
2023*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO,
2024*2d1d418eSSumit Saxena 		      "Issue CI Header Upload:EnvVariableOffset(0x%x) \
2025*2d1d418eSSumit Saxena 		      HeaderSize(0x%x) Signature1(0x%x)\n",
2026*2d1d418eSSumit Saxena 		      ci_header->EnvironmentVariableOffset,
2027*2d1d418eSSumit Saxena 		      ci_header->HeaderSize,
2028*2d1d418eSSumit Saxena 		      ci_header->Signature1);
2029*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "FW Package Version: %02d.%02d.%02d.%02d\n",
2030*2d1d418eSSumit Saxena 		      ci_header->ComponentImageVersion.GenMajor,
2031*2d1d418eSSumit Saxena 		      ci_header->ComponentImageVersion.GenMinor,
2032*2d1d418eSSumit Saxena 		      ci_header->ComponentImageVersion.PhaseMajor,
2033*2d1d418eSSumit Saxena 		      ci_header->ComponentImageVersion.PhaseMinor);
2034*2d1d418eSSumit Saxena out_unlock:
2035*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2036*2d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
2037*2d1d418eSSumit Saxena 
2038*2d1d418eSSumit Saxena out:
2039*2d1d418eSSumit Saxena 	if (fw_pkg_ver_dma != 0)
2040*2d1d418eSSumit Saxena 		bus_dmamap_unload(fw_pkg_ver_tag, fw_pkg_ver_map);
2041*2d1d418eSSumit Saxena 	if (fw_pkg_ver)
2042*2d1d418eSSumit Saxena 		bus_dmamem_free(fw_pkg_ver_tag, fw_pkg_ver, fw_pkg_ver_map);
2043*2d1d418eSSumit Saxena 	if (fw_pkg_ver_tag)
2044*2d1d418eSSumit Saxena 		bus_dma_tag_destroy(fw_pkg_ver_tag);
2045*2d1d418eSSumit Saxena 
2046*2d1d418eSSumit Saxena }
2047*2d1d418eSSumit Saxena 
2048*2d1d418eSSumit Saxena /**
2049*2d1d418eSSumit Saxena  * mpi3mr_issue_iocinit - Send IOC Init
2050*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
2051*2d1d418eSSumit Saxena  *
2052*2d1d418eSSumit Saxena  * Issue IOC Init MPI request through admin queue and wait for
2053*2d1d418eSSumit Saxena  * the completion of it or time out.
2054*2d1d418eSSumit Saxena  *
2055*2d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failures.
2056*2d1d418eSSumit Saxena  */
2057*2d1d418eSSumit Saxena static int mpi3mr_issue_iocinit(struct mpi3mr_softc *sc)
2058*2d1d418eSSumit Saxena {
2059*2d1d418eSSumit Saxena 	Mpi3IOCInitRequest_t iocinit_req;
2060*2d1d418eSSumit Saxena 	Mpi3DriverInfoLayout_t *drvr_info = NULL;
2061*2d1d418eSSumit Saxena 	bus_dma_tag_t drvr_info_tag;
2062*2d1d418eSSumit Saxena 	bus_dmamap_t drvr_info_map;
2063*2d1d418eSSumit Saxena 	bus_addr_t drvr_info_phys;
2064*2d1d418eSSumit Saxena 	U32 drvr_info_len = sizeof(*drvr_info);
2065*2d1d418eSSumit Saxena 	int retval = 0;
2066*2d1d418eSSumit Saxena 	struct timeval now;
2067*2d1d418eSSumit Saxena 	uint64_t time_in_msec;
2068*2d1d418eSSumit Saxena 
2069*2d1d418eSSumit Saxena 	if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,  /* parent */
2070*2d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
2071*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
2072*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
2073*2d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
2074*2d1d418eSSumit Saxena                                 drvr_info_len,		/* maxsize */
2075*2d1d418eSSumit Saxena                                 1,			/* nsegments */
2076*2d1d418eSSumit Saxena                                 drvr_info_len,		/* maxsegsize */
2077*2d1d418eSSumit Saxena                                 0,			/* flags */
2078*2d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
2079*2d1d418eSSumit Saxena                                 &drvr_info_tag)) {
2080*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
2081*2d1d418eSSumit Saxena 		return (ENOMEM);
2082*2d1d418eSSumit Saxena         }
2083*2d1d418eSSumit Saxena 
2084*2d1d418eSSumit Saxena 	if (bus_dmamem_alloc(drvr_info_tag, (void **)&drvr_info,
2085*2d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &drvr_info_map)) {
2086*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d Data  DMA mem alloc failed\n",
2087*2d1d418eSSumit Saxena 			__func__, __LINE__);
2088*2d1d418eSSumit Saxena 		return (ENOMEM);
2089*2d1d418eSSumit Saxena         }
2090*2d1d418eSSumit Saxena 
2091*2d1d418eSSumit Saxena 	bzero(drvr_info, drvr_info_len);
2092*2d1d418eSSumit Saxena         bus_dmamap_load(drvr_info_tag, drvr_info_map, drvr_info, drvr_info_len,
2093*2d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &drvr_info_phys, 0);
2094*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d IOCfacts drvr_info phys addr= %#016jx size= %d\n",
2095*2d1d418eSSumit Saxena 	    __func__, __LINE__, (uintmax_t)drvr_info_phys, drvr_info_len);
2096*2d1d418eSSumit Saxena 
2097*2d1d418eSSumit Saxena 	if (!drvr_info)
2098*2d1d418eSSumit Saxena 	{
2099*2d1d418eSSumit Saxena 		retval = -1;
2100*2d1d418eSSumit Saxena 		printf(IOCNAME "Memory alloc for Driver Info failed\n",
2101*2d1d418eSSumit Saxena 		    sc->name);
2102*2d1d418eSSumit Saxena 		goto out;
2103*2d1d418eSSumit Saxena 	}
2104*2d1d418eSSumit Saxena 	drvr_info->InformationLength = (drvr_info_len);
2105*2d1d418eSSumit Saxena 	strcpy(drvr_info->DriverSignature, "Broadcom");
2106*2d1d418eSSumit Saxena 	strcpy(drvr_info->OsName, "FreeBSD");
2107*2d1d418eSSumit Saxena 	strcpy(drvr_info->OsVersion, fmt_os_ver);
2108*2d1d418eSSumit Saxena 	strcpy(drvr_info->DriverName, MPI3MR_DRIVER_NAME);
2109*2d1d418eSSumit Saxena 	strcpy(drvr_info->DriverVersion, MPI3MR_DRIVER_VERSION);
2110*2d1d418eSSumit Saxena 	strcpy(drvr_info->DriverReleaseDate, MPI3MR_DRIVER_RELDATE);
2111*2d1d418eSSumit Saxena 	drvr_info->DriverCapabilities = 0;
2112*2d1d418eSSumit Saxena 	memcpy((U8 *)&sc->driver_info, (U8 *)drvr_info, sizeof(sc->driver_info));
2113*2d1d418eSSumit Saxena 
2114*2d1d418eSSumit Saxena 	memset(&iocinit_req, 0, sizeof(iocinit_req));
2115*2d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
2116*2d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
2117*2d1d418eSSumit Saxena 		retval = -1;
2118*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCInit: Init command is in use\n",
2119*2d1d418eSSumit Saxena 		    sc->name);
2120*2d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
2121*2d1d418eSSumit Saxena 		goto out;
2122*2d1d418eSSumit Saxena 	}
2123*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
2124*2d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
2125*2d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
2126*2d1d418eSSumit Saxena         iocinit_req.HostTag = MPI3MR_HOSTTAG_INITCMDS;
2127*2d1d418eSSumit Saxena         iocinit_req.Function = MPI3_FUNCTION_IOC_INIT;
2128*2d1d418eSSumit Saxena         iocinit_req.MPIVersion.Struct.Dev = MPI3_VERSION_DEV;
2129*2d1d418eSSumit Saxena         iocinit_req.MPIVersion.Struct.Unit = MPI3_VERSION_UNIT;
2130*2d1d418eSSumit Saxena         iocinit_req.MPIVersion.Struct.Major = MPI3_VERSION_MAJOR;
2131*2d1d418eSSumit Saxena         iocinit_req.MPIVersion.Struct.Minor = MPI3_VERSION_MINOR;
2132*2d1d418eSSumit Saxena         iocinit_req.WhoInit = MPI3_WHOINIT_HOST_DRIVER;
2133*2d1d418eSSumit Saxena         iocinit_req.ReplyFreeQueueDepth = sc->reply_free_q_sz;
2134*2d1d418eSSumit Saxena         iocinit_req.ReplyFreeQueueAddress =
2135*2d1d418eSSumit Saxena                 sc->reply_free_q_phys;
2136*2d1d418eSSumit Saxena         iocinit_req.SenseBufferLength = MPI3MR_SENSEBUF_SZ;
2137*2d1d418eSSumit Saxena         iocinit_req.SenseBufferFreeQueueDepth =
2138*2d1d418eSSumit Saxena                 sc->sense_buf_q_sz;
2139*2d1d418eSSumit Saxena         iocinit_req.SenseBufferFreeQueueAddress =
2140*2d1d418eSSumit Saxena                 sc->sense_buf_q_phys;
2141*2d1d418eSSumit Saxena         iocinit_req.DriverInformationAddress = drvr_info_phys;
2142*2d1d418eSSumit Saxena 
2143*2d1d418eSSumit Saxena 	getmicrotime(&now);
2144*2d1d418eSSumit Saxena 	time_in_msec = (now.tv_sec * 1000 + now.tv_usec/1000);
2145*2d1d418eSSumit Saxena 	iocinit_req.TimeStamp = htole64(time_in_msec);
2146*2d1d418eSSumit Saxena 
2147*2d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
2148*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &iocinit_req,
2149*2d1d418eSSumit Saxena 	    sizeof(iocinit_req));
2150*2d1d418eSSumit Saxena 
2151*2d1d418eSSumit Saxena 	if (retval) {
2152*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCInit: Admin Post failed\n",
2153*2d1d418eSSumit Saxena 		    sc->name);
2154*2d1d418eSSumit Saxena 		goto out_unlock;
2155*2d1d418eSSumit Saxena 	}
2156*2d1d418eSSumit Saxena 
2157*2d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
2158*2d1d418eSSumit Saxena 	    (MPI3MR_INTADMCMD_TIMEOUT));
2159*2d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2160*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCInit: command timed out\n",
2161*2d1d418eSSumit Saxena 		    sc->name);
2162*2d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
2163*2d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_IOCINIT_TIMEOUT);
2164*2d1d418eSSumit Saxena 		sc->unrecoverable = 1;
2165*2d1d418eSSumit Saxena 		retval = -1;
2166*2d1d418eSSumit Saxena 		goto out_unlock;
2167*2d1d418eSSumit Saxena 	}
2168*2d1d418eSSumit Saxena 
2169*2d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2170*2d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
2171*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCInit: Failed IOCStatus(0x%04x) "
2172*2d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
2173*2d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2174*2d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
2175*2d1d418eSSumit Saxena 		retval = -1;
2176*2d1d418eSSumit Saxena 		goto out_unlock;
2177*2d1d418eSSumit Saxena 	}
2178*2d1d418eSSumit Saxena 
2179*2d1d418eSSumit Saxena out_unlock:
2180*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2181*2d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
2182*2d1d418eSSumit Saxena 
2183*2d1d418eSSumit Saxena out:
2184*2d1d418eSSumit Saxena 	if (drvr_info_phys != 0)
2185*2d1d418eSSumit Saxena 		bus_dmamap_unload(drvr_info_tag, drvr_info_map);
2186*2d1d418eSSumit Saxena 	if (drvr_info != NULL)
2187*2d1d418eSSumit Saxena 		bus_dmamem_free(drvr_info_tag, drvr_info, drvr_info_map);
2188*2d1d418eSSumit Saxena 	if (drvr_info_tag != NULL)
2189*2d1d418eSSumit Saxena 		bus_dma_tag_destroy(drvr_info_tag);
2190*2d1d418eSSumit Saxena 	return retval;
2191*2d1d418eSSumit Saxena }
2192*2d1d418eSSumit Saxena 
2193*2d1d418eSSumit Saxena static void
2194*2d1d418eSSumit Saxena mpi3mr_display_ioc_info(struct mpi3mr_softc *sc)
2195*2d1d418eSSumit Saxena {
2196*2d1d418eSSumit Saxena         int i = 0;
2197*2d1d418eSSumit Saxena         char personality[16];
2198*2d1d418eSSumit Saxena         struct mpi3mr_compimg_ver *fwver = &sc->facts.fw_ver;
2199*2d1d418eSSumit Saxena 
2200*2d1d418eSSumit Saxena         switch (sc->facts.personality) {
2201*2d1d418eSSumit Saxena         case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA:
2202*2d1d418eSSumit Saxena                 strcpy(personality, "Enhanced HBA");
2203*2d1d418eSSumit Saxena                 break;
2204*2d1d418eSSumit Saxena         case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR:
2205*2d1d418eSSumit Saxena                 strcpy(personality, "RAID");
2206*2d1d418eSSumit Saxena                 break;
2207*2d1d418eSSumit Saxena         default:
2208*2d1d418eSSumit Saxena                 strcpy(personality, "Unknown");
2209*2d1d418eSSumit Saxena                 break;
2210*2d1d418eSSumit Saxena         }
2211*2d1d418eSSumit Saxena 
2212*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "Current Personality: %s\n", personality);
2213*2d1d418eSSumit Saxena 
2214*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "FW Version: %d.%d.%d.%d.%05d-%05d\n",
2215*2d1d418eSSumit Saxena 		      fwver->gen_major, fwver->gen_minor, fwver->ph_major,
2216*2d1d418eSSumit Saxena 		      fwver->ph_minor, fwver->cust_id, fwver->build_num);
2217*2d1d418eSSumit Saxena 
2218*2d1d418eSSumit Saxena         mpi3mr_dprint(sc, MPI3MR_INFO, "Protocol=(");
2219*2d1d418eSSumit Saxena 
2220*2d1d418eSSumit Saxena         if (sc->facts.protocol_flags &
2221*2d1d418eSSumit Saxena             MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR) {
2222*2d1d418eSSumit Saxena                 printf("Initiator");
2223*2d1d418eSSumit Saxena                 i++;
2224*2d1d418eSSumit Saxena         }
2225*2d1d418eSSumit Saxena 
2226*2d1d418eSSumit Saxena         if (sc->facts.protocol_flags &
2227*2d1d418eSSumit Saxena             MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET) {
2228*2d1d418eSSumit Saxena                 printf("%sTarget", i ? "," : "");
2229*2d1d418eSSumit Saxena                 i++;
2230*2d1d418eSSumit Saxena         }
2231*2d1d418eSSumit Saxena 
2232*2d1d418eSSumit Saxena         if (sc->facts.protocol_flags &
2233*2d1d418eSSumit Saxena             MPI3_IOCFACTS_PROTOCOL_NVME) {
2234*2d1d418eSSumit Saxena                 printf("%sNVMe attachment", i ? "," : "");
2235*2d1d418eSSumit Saxena                 i++;
2236*2d1d418eSSumit Saxena         }
2237*2d1d418eSSumit Saxena         i = 0;
2238*2d1d418eSSumit Saxena         printf("), ");
2239*2d1d418eSSumit Saxena         printf("Capabilities=(");
2240*2d1d418eSSumit Saxena 
2241*2d1d418eSSumit Saxena         if (sc->facts.ioc_capabilities &
2242*2d1d418eSSumit Saxena             MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE) {
2243*2d1d418eSSumit Saxena                 printf("RAID");
2244*2d1d418eSSumit Saxena                 i++;
2245*2d1d418eSSumit Saxena         }
2246*2d1d418eSSumit Saxena 
2247*2d1d418eSSumit Saxena         printf(")\n");
2248*2d1d418eSSumit Saxena }
2249*2d1d418eSSumit Saxena 
2250*2d1d418eSSumit Saxena /**
2251*2d1d418eSSumit Saxena  * mpi3mr_unmask_events - Unmask events in event mask bitmap
2252*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
2253*2d1d418eSSumit Saxena  * @event: MPI event ID
2254*2d1d418eSSumit Saxena  *
2255*2d1d418eSSumit Saxena  * Un mask the specific event by resetting the event_mask
2256*2d1d418eSSumit Saxena  * bitmap.
2257*2d1d418eSSumit Saxena  *
2258*2d1d418eSSumit Saxena  * Return: None.
2259*2d1d418eSSumit Saxena  */
2260*2d1d418eSSumit Saxena static void mpi3mr_unmask_events(struct mpi3mr_softc *sc, U16 event)
2261*2d1d418eSSumit Saxena {
2262*2d1d418eSSumit Saxena 	U32 desired_event;
2263*2d1d418eSSumit Saxena 
2264*2d1d418eSSumit Saxena 	if (event >= 128)
2265*2d1d418eSSumit Saxena 		return;
2266*2d1d418eSSumit Saxena 
2267*2d1d418eSSumit Saxena 	desired_event = (1 << (event % 32));
2268*2d1d418eSSumit Saxena 
2269*2d1d418eSSumit Saxena 	if (event < 32)
2270*2d1d418eSSumit Saxena 		sc->event_masks[0] &= ~desired_event;
2271*2d1d418eSSumit Saxena 	else if (event < 64)
2272*2d1d418eSSumit Saxena 		sc->event_masks[1] &= ~desired_event;
2273*2d1d418eSSumit Saxena 	else if (event < 96)
2274*2d1d418eSSumit Saxena 		sc->event_masks[2] &= ~desired_event;
2275*2d1d418eSSumit Saxena 	else if (event < 128)
2276*2d1d418eSSumit Saxena 		sc->event_masks[3] &= ~desired_event;
2277*2d1d418eSSumit Saxena }
2278*2d1d418eSSumit Saxena 
2279*2d1d418eSSumit Saxena static void mpi3mr_set_events_mask(struct mpi3mr_softc *sc)
2280*2d1d418eSSumit Saxena {
2281*2d1d418eSSumit Saxena 	int i;
2282*2d1d418eSSumit Saxena 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
2283*2d1d418eSSumit Saxena 		sc->event_masks[i] = -1;
2284*2d1d418eSSumit Saxena 
2285*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_DEVICE_ADDED);
2286*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_DEVICE_INFO_CHANGED);
2287*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
2288*2d1d418eSSumit Saxena 
2289*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
2290*2d1d418eSSumit Saxena 
2291*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
2292*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_DISCOVERY);
2293*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
2294*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE);
2295*2d1d418eSSumit Saxena 
2296*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
2297*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_PCIE_ENUMERATION);
2298*2d1d418eSSumit Saxena 
2299*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_PREPARE_FOR_RESET);
2300*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_CABLE_MGMT);
2301*2d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_ENERGY_PACK_CHANGE);
2302*2d1d418eSSumit Saxena }
2303*2d1d418eSSumit Saxena 
2304*2d1d418eSSumit Saxena /**
2305*2d1d418eSSumit Saxena  * mpi3mr_issue_event_notification - Send event notification
2306*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
2307*2d1d418eSSumit Saxena  *
2308*2d1d418eSSumit Saxena  * Issue event notification MPI request through admin queue and
2309*2d1d418eSSumit Saxena  * wait for the completion of it or time out.
2310*2d1d418eSSumit Saxena  *
2311*2d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failures.
2312*2d1d418eSSumit Saxena  */
2313*2d1d418eSSumit Saxena int mpi3mr_issue_event_notification(struct mpi3mr_softc *sc)
2314*2d1d418eSSumit Saxena {
2315*2d1d418eSSumit Saxena 	Mpi3EventNotificationRequest_t evtnotify_req;
2316*2d1d418eSSumit Saxena 	int retval = 0;
2317*2d1d418eSSumit Saxena 	U8 i;
2318*2d1d418eSSumit Saxena 
2319*2d1d418eSSumit Saxena 	memset(&evtnotify_req, 0, sizeof(evtnotify_req));
2320*2d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
2321*2d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
2322*2d1d418eSSumit Saxena 		retval = -1;
2323*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtNotify: Init command is in use\n",
2324*2d1d418eSSumit Saxena 		    sc->name);
2325*2d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
2326*2d1d418eSSumit Saxena 		goto out;
2327*2d1d418eSSumit Saxena 	}
2328*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
2329*2d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
2330*2d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
2331*2d1d418eSSumit Saxena 	evtnotify_req.HostTag = (MPI3MR_HOSTTAG_INITCMDS);
2332*2d1d418eSSumit Saxena 	evtnotify_req.Function = MPI3_FUNCTION_EVENT_NOTIFICATION;
2333*2d1d418eSSumit Saxena 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
2334*2d1d418eSSumit Saxena 		evtnotify_req.EventMasks[i] =
2335*2d1d418eSSumit Saxena 		    (sc->event_masks[i]);
2336*2d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
2337*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &evtnotify_req,
2338*2d1d418eSSumit Saxena 	    sizeof(evtnotify_req));
2339*2d1d418eSSumit Saxena 	if (retval) {
2340*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtNotify: Admin Post failed\n",
2341*2d1d418eSSumit Saxena 		    sc->name);
2342*2d1d418eSSumit Saxena 		goto out_unlock;
2343*2d1d418eSSumit Saxena 	}
2344*2d1d418eSSumit Saxena 
2345*2d1d418eSSumit Saxena 	poll_for_command_completion(sc,
2346*2d1d418eSSumit Saxena 				    &sc->init_cmds,
2347*2d1d418eSSumit Saxena 				    (MPI3MR_INTADMCMD_TIMEOUT));
2348*2d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2349*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtNotify: command timed out\n",
2350*2d1d418eSSumit Saxena 		    sc->name);
2351*2d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
2352*2d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT);
2353*2d1d418eSSumit Saxena 		retval = -1;
2354*2d1d418eSSumit Saxena 		goto out_unlock;
2355*2d1d418eSSumit Saxena 	}
2356*2d1d418eSSumit Saxena 
2357*2d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2358*2d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
2359*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtNotify: Failed IOCStatus(0x%04x) "
2360*2d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
2361*2d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2362*2d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
2363*2d1d418eSSumit Saxena 		retval = -1;
2364*2d1d418eSSumit Saxena 		goto out_unlock;
2365*2d1d418eSSumit Saxena 	}
2366*2d1d418eSSumit Saxena 
2367*2d1d418eSSumit Saxena out_unlock:
2368*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2369*2d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
2370*2d1d418eSSumit Saxena 
2371*2d1d418eSSumit Saxena out:
2372*2d1d418eSSumit Saxena 	return retval;
2373*2d1d418eSSumit Saxena }
2374*2d1d418eSSumit Saxena 
2375*2d1d418eSSumit Saxena int
2376*2d1d418eSSumit Saxena mpi3mr_register_events(struct mpi3mr_softc *sc)
2377*2d1d418eSSumit Saxena {
2378*2d1d418eSSumit Saxena 	int error;
2379*2d1d418eSSumit Saxena 
2380*2d1d418eSSumit Saxena 	mpi3mr_set_events_mask(sc);
2381*2d1d418eSSumit Saxena 
2382*2d1d418eSSumit Saxena 	error = mpi3mr_issue_event_notification(sc);
2383*2d1d418eSSumit Saxena 
2384*2d1d418eSSumit Saxena 	if (error) {
2385*2d1d418eSSumit Saxena 		printf(IOCNAME "Failed to issue event notification %d\n",
2386*2d1d418eSSumit Saxena 		    sc->name, error);
2387*2d1d418eSSumit Saxena 	}
2388*2d1d418eSSumit Saxena 
2389*2d1d418eSSumit Saxena 	return error;
2390*2d1d418eSSumit Saxena }
2391*2d1d418eSSumit Saxena 
2392*2d1d418eSSumit Saxena /**
2393*2d1d418eSSumit Saxena  * mpi3mr_process_event_ack - Process event acknowledgment
2394*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
2395*2d1d418eSSumit Saxena  * @event: MPI3 event ID
2396*2d1d418eSSumit Saxena  * @event_ctx: Event context
2397*2d1d418eSSumit Saxena  *
2398*2d1d418eSSumit Saxena  * Send event acknowledgement through admin queue and wait for
2399*2d1d418eSSumit Saxena  * it to complete.
2400*2d1d418eSSumit Saxena  *
2401*2d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failures.
2402*2d1d418eSSumit Saxena  */
2403*2d1d418eSSumit Saxena int mpi3mr_process_event_ack(struct mpi3mr_softc *sc, U8 event,
2404*2d1d418eSSumit Saxena 	U32 event_ctx)
2405*2d1d418eSSumit Saxena {
2406*2d1d418eSSumit Saxena 	Mpi3EventAckRequest_t evtack_req;
2407*2d1d418eSSumit Saxena 	int retval = 0;
2408*2d1d418eSSumit Saxena 
2409*2d1d418eSSumit Saxena 	memset(&evtack_req, 0, sizeof(evtack_req));
2410*2d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
2411*2d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
2412*2d1d418eSSumit Saxena 		retval = -1;
2413*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtAck: Init command is in use\n",
2414*2d1d418eSSumit Saxena 		    sc->name);
2415*2d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
2416*2d1d418eSSumit Saxena 		goto out;
2417*2d1d418eSSumit Saxena 	}
2418*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
2419*2d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
2420*2d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
2421*2d1d418eSSumit Saxena 	evtack_req.HostTag = htole16(MPI3MR_HOSTTAG_INITCMDS);
2422*2d1d418eSSumit Saxena 	evtack_req.Function = MPI3_FUNCTION_EVENT_ACK;
2423*2d1d418eSSumit Saxena 	evtack_req.Event = event;
2424*2d1d418eSSumit Saxena 	evtack_req.EventContext = htole32(event_ctx);
2425*2d1d418eSSumit Saxena 
2426*2d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
2427*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &evtack_req,
2428*2d1d418eSSumit Saxena 	    sizeof(evtack_req));
2429*2d1d418eSSumit Saxena 	if (retval) {
2430*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtAck: Admin Post failed\n",
2431*2d1d418eSSumit Saxena 		    sc->name);
2432*2d1d418eSSumit Saxena 		goto out_unlock;
2433*2d1d418eSSumit Saxena 	}
2434*2d1d418eSSumit Saxena 
2435*2d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
2436*2d1d418eSSumit Saxena 	    (MPI3MR_INTADMCMD_TIMEOUT));
2437*2d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
2438*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtAck: command timed out\n",
2439*2d1d418eSSumit Saxena 		    sc->name);
2440*2d1d418eSSumit Saxena 		retval = -1;
2441*2d1d418eSSumit Saxena 		goto out_unlock;
2442*2d1d418eSSumit Saxena 	}
2443*2d1d418eSSumit Saxena 
2444*2d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
2445*2d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
2446*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtAck: Failed IOCStatus(0x%04x) "
2447*2d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
2448*2d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
2449*2d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
2450*2d1d418eSSumit Saxena 		retval = -1;
2451*2d1d418eSSumit Saxena 		goto out_unlock;
2452*2d1d418eSSumit Saxena 	}
2453*2d1d418eSSumit Saxena 
2454*2d1d418eSSumit Saxena out_unlock:
2455*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2456*2d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
2457*2d1d418eSSumit Saxena 
2458*2d1d418eSSumit Saxena out:
2459*2d1d418eSSumit Saxena 	return retval;
2460*2d1d418eSSumit Saxena }
2461*2d1d418eSSumit Saxena 
2462*2d1d418eSSumit Saxena 
2463*2d1d418eSSumit Saxena static int mpi3mr_alloc_chain_bufs(struct mpi3mr_softc *sc)
2464*2d1d418eSSumit Saxena {
2465*2d1d418eSSumit Saxena 	int retval = 0;
2466*2d1d418eSSumit Saxena 	U32 sz, i;
2467*2d1d418eSSumit Saxena 	U16 num_chains;
2468*2d1d418eSSumit Saxena 
2469*2d1d418eSSumit Saxena 	num_chains = sc->max_host_ios;
2470*2d1d418eSSumit Saxena 
2471*2d1d418eSSumit Saxena 	sc->chain_buf_count = num_chains;
2472*2d1d418eSSumit Saxena 	sz = sizeof(struct mpi3mr_chain) * num_chains;
2473*2d1d418eSSumit Saxena 
2474*2d1d418eSSumit Saxena 	sc->chain_sgl_list = malloc(sz, M_MPI3MR, M_NOWAIT | M_ZERO);
2475*2d1d418eSSumit Saxena 
2476*2d1d418eSSumit Saxena 	if (!sc->chain_sgl_list) {
2477*2d1d418eSSumit Saxena 		printf(IOCNAME "Cannot allocate memory for chain SGL list\n",
2478*2d1d418eSSumit Saxena 		    sc->name);
2479*2d1d418eSSumit Saxena 		retval = -1;
2480*2d1d418eSSumit Saxena 		goto out_failed;
2481*2d1d418eSSumit Saxena 	}
2482*2d1d418eSSumit Saxena 
2483*2d1d418eSSumit Saxena 	sz = MPI3MR_CHAINSGE_SIZE;
2484*2d1d418eSSumit Saxena 
2485*2d1d418eSSumit Saxena         if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,  /* parent */
2486*2d1d418eSSumit Saxena 				4096, 0,		/* algnmnt, boundary */
2487*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
2488*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
2489*2d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
2490*2d1d418eSSumit Saxena                                 sz,			/* maxsize */
2491*2d1d418eSSumit Saxena                                 1,			/* nsegments */
2492*2d1d418eSSumit Saxena                                 sz,			/* maxsegsize */
2493*2d1d418eSSumit Saxena                                 0,			/* flags */
2494*2d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
2495*2d1d418eSSumit Saxena                                 &sc->chain_sgl_list_tag)) {
2496*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Chain buffer DMA tag\n");
2497*2d1d418eSSumit Saxena 		return (ENOMEM);
2498*2d1d418eSSumit Saxena         }
2499*2d1d418eSSumit Saxena 
2500*2d1d418eSSumit Saxena 	for (i = 0; i < num_chains; i++) {
2501*2d1d418eSSumit Saxena 		if (bus_dmamem_alloc(sc->chain_sgl_list_tag, (void **)&sc->chain_sgl_list[i].buf,
2502*2d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &sc->chain_sgl_list[i].buf_dmamap)) {
2503*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d  DMA mem alloc failed\n",
2504*2d1d418eSSumit Saxena 				__func__, __LINE__);
2505*2d1d418eSSumit Saxena 			return (ENOMEM);
2506*2d1d418eSSumit Saxena 		}
2507*2d1d418eSSumit Saxena 
2508*2d1d418eSSumit Saxena 		bzero(sc->chain_sgl_list[i].buf, sz);
2509*2d1d418eSSumit Saxena 		bus_dmamap_load(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf_dmamap, sc->chain_sgl_list[i].buf, sz,
2510*2d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &sc->chain_sgl_list[i].buf_phys, 0);
2511*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d phys addr= %#016jx size= %d\n",
2512*2d1d418eSSumit Saxena 		    __func__, __LINE__, (uintmax_t)sc->chain_sgl_list[i].buf_phys, sz);
2513*2d1d418eSSumit Saxena 	}
2514*2d1d418eSSumit Saxena 
2515*2d1d418eSSumit Saxena 	sc->chain_bitmap_sz = MPI3MR_DIV_ROUND_UP(num_chains, 8);
2516*2d1d418eSSumit Saxena 
2517*2d1d418eSSumit Saxena 	sc->chain_bitmap = malloc(sc->chain_bitmap_sz, M_MPI3MR, M_NOWAIT | M_ZERO);
2518*2d1d418eSSumit Saxena 	if (!sc->chain_bitmap) {
2519*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "Cannot alloc memory for chain bitmap\n");
2520*2d1d418eSSumit Saxena 		retval = -1;
2521*2d1d418eSSumit Saxena 		goto out_failed;
2522*2d1d418eSSumit Saxena 	}
2523*2d1d418eSSumit Saxena 	return retval;
2524*2d1d418eSSumit Saxena 
2525*2d1d418eSSumit Saxena out_failed:
2526*2d1d418eSSumit Saxena 	for (i = 0; i < num_chains; i++) {
2527*2d1d418eSSumit Saxena 		if (sc->chain_sgl_list[i].buf_phys != 0)
2528*2d1d418eSSumit Saxena 			bus_dmamap_unload(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf_dmamap);
2529*2d1d418eSSumit Saxena 		if (sc->chain_sgl_list[i].buf != NULL)
2530*2d1d418eSSumit Saxena 			bus_dmamem_free(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf, sc->chain_sgl_list[i].buf_dmamap);
2531*2d1d418eSSumit Saxena 	}
2532*2d1d418eSSumit Saxena 	if (sc->chain_sgl_list_tag != NULL)
2533*2d1d418eSSumit Saxena 		bus_dma_tag_destroy(sc->chain_sgl_list_tag);
2534*2d1d418eSSumit Saxena 	return retval;
2535*2d1d418eSSumit Saxena }
2536*2d1d418eSSumit Saxena 
2537*2d1d418eSSumit Saxena static int mpi3mr_pel_alloc(struct mpi3mr_softc *sc)
2538*2d1d418eSSumit Saxena {
2539*2d1d418eSSumit Saxena 	int retval = 0;
2540*2d1d418eSSumit Saxena 
2541*2d1d418eSSumit Saxena 	if (!sc->pel_cmds.reply) {
2542*2d1d418eSSumit Saxena 		sc->pel_cmds.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO);
2543*2d1d418eSSumit Saxena 		if (!sc->pel_cmds.reply) {
2544*2d1d418eSSumit Saxena 			printf(IOCNAME "Cannot allocate memory for pel_cmds.reply\n",
2545*2d1d418eSSumit Saxena 			    sc->name);
2546*2d1d418eSSumit Saxena 			goto out_failed;
2547*2d1d418eSSumit Saxena 		}
2548*2d1d418eSSumit Saxena 	}
2549*2d1d418eSSumit Saxena 
2550*2d1d418eSSumit Saxena 	if (!sc->pel_abort_cmd.reply) {
2551*2d1d418eSSumit Saxena 		sc->pel_abort_cmd.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO);
2552*2d1d418eSSumit Saxena 		if (!sc->pel_abort_cmd.reply) {
2553*2d1d418eSSumit Saxena 			printf(IOCNAME "Cannot allocate memory for pel_abort_cmd.reply\n",
2554*2d1d418eSSumit Saxena 			    sc->name);
2555*2d1d418eSSumit Saxena 			goto out_failed;
2556*2d1d418eSSumit Saxena 		}
2557*2d1d418eSSumit Saxena 	}
2558*2d1d418eSSumit Saxena 
2559*2d1d418eSSumit Saxena 	if (!sc->pel_seq_number) {
2560*2d1d418eSSumit Saxena 		sc->pel_seq_number_sz = sizeof(Mpi3PELSeq_t);
2561*2d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,   /* parent */
2562*2d1d418eSSumit Saxena 				 4, 0,                           /* alignment, boundary */
2563*2d1d418eSSumit Saxena 				 BUS_SPACE_MAXADDR_32BIT,        /* lowaddr */
2564*2d1d418eSSumit Saxena 				 BUS_SPACE_MAXADDR,              /* highaddr */
2565*2d1d418eSSumit Saxena 				 NULL, NULL,                     /* filter, filterarg */
2566*2d1d418eSSumit Saxena 				 sc->pel_seq_number_sz,		 /* maxsize */
2567*2d1d418eSSumit Saxena 				 1,                              /* nsegments */
2568*2d1d418eSSumit Saxena 				 sc->pel_seq_number_sz,          /* maxsegsize */
2569*2d1d418eSSumit Saxena 				 0,                              /* flags */
2570*2d1d418eSSumit Saxena 				 NULL, NULL,                     /* lockfunc, lockarg */
2571*2d1d418eSSumit Saxena 				 &sc->pel_seq_num_dmatag)) {
2572*2d1d418eSSumit Saxena 			 mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot create PEL seq number dma memory tag\n");
2573*2d1d418eSSumit Saxena 			 retval = -ENOMEM;
2574*2d1d418eSSumit Saxena 			 goto out_failed;
2575*2d1d418eSSumit Saxena 		}
2576*2d1d418eSSumit Saxena 
2577*2d1d418eSSumit Saxena 		if (bus_dmamem_alloc(sc->pel_seq_num_dmatag, (void **)&sc->pel_seq_number,
2578*2d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &sc->pel_seq_num_dmamap)) {
2579*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate PEL seq number kernel buffer dma memory\n");
2580*2d1d418eSSumit Saxena 			retval = -ENOMEM;
2581*2d1d418eSSumit Saxena 			goto out_failed;
2582*2d1d418eSSumit Saxena 		}
2583*2d1d418eSSumit Saxena 
2584*2d1d418eSSumit Saxena 		bzero(sc->pel_seq_number, sc->pel_seq_number_sz);
2585*2d1d418eSSumit Saxena 
2586*2d1d418eSSumit Saxena 		bus_dmamap_load(sc->pel_seq_num_dmatag, sc->pel_seq_num_dmamap, sc->pel_seq_number,
2587*2d1d418eSSumit Saxena 		    sc->pel_seq_number_sz, mpi3mr_memaddr_cb, &sc->pel_seq_number_dma, 0);
2588*2d1d418eSSumit Saxena 
2589*2d1d418eSSumit Saxena 		if (!sc->pel_seq_number) {
2590*2d1d418eSSumit Saxena 			printf(IOCNAME "%s:%d Cannot load PEL seq number dma memory for size: %d\n", sc->name,
2591*2d1d418eSSumit Saxena 				__func__, __LINE__, sc->pel_seq_number_sz);
2592*2d1d418eSSumit Saxena 			retval = -ENOMEM;
2593*2d1d418eSSumit Saxena 			goto out_failed;
2594*2d1d418eSSumit Saxena 		}
2595*2d1d418eSSumit Saxena 	}
2596*2d1d418eSSumit Saxena 
2597*2d1d418eSSumit Saxena out_failed:
2598*2d1d418eSSumit Saxena 	return retval;
2599*2d1d418eSSumit Saxena }
2600*2d1d418eSSumit Saxena 
2601*2d1d418eSSumit Saxena /**
2602*2d1d418eSSumit Saxena  * mpi3mr_validate_fw_update - validate IOCFacts post adapter reset
2603*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
2604*2d1d418eSSumit Saxena  *
2605*2d1d418eSSumit Saxena  * Return zero if the new IOCFacts is compatible with previous values
2606*2d1d418eSSumit Saxena  * else return appropriate error
2607*2d1d418eSSumit Saxena  */
2608*2d1d418eSSumit Saxena static int
2609*2d1d418eSSumit Saxena mpi3mr_validate_fw_update(struct mpi3mr_softc *sc)
2610*2d1d418eSSumit Saxena {
2611*2d1d418eSSumit Saxena 	U16 dev_handle_bitmap_sz;
2612*2d1d418eSSumit Saxena 	U8 *removepend_bitmap;
2613*2d1d418eSSumit Saxena 
2614*2d1d418eSSumit Saxena 	if (sc->facts.reply_sz > sc->reply_sz) {
2615*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
2616*2d1d418eSSumit Saxena 		    "Cannot increase reply size from %d to %d\n",
2617*2d1d418eSSumit Saxena 		    sc->reply_sz, sc->reply_sz);
2618*2d1d418eSSumit Saxena 		return -EPERM;
2619*2d1d418eSSumit Saxena 	}
2620*2d1d418eSSumit Saxena 
2621*2d1d418eSSumit Saxena 	if (sc->num_io_throttle_group != sc->facts.max_io_throttle_group) {
2622*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
2623*2d1d418eSSumit Saxena 		    "max io throttle group doesn't match old(%d), new(%d)\n",
2624*2d1d418eSSumit Saxena 		    sc->num_io_throttle_group,
2625*2d1d418eSSumit Saxena 		    sc->facts.max_io_throttle_group);
2626*2d1d418eSSumit Saxena 		return -EPERM;
2627*2d1d418eSSumit Saxena 	}
2628*2d1d418eSSumit Saxena 
2629*2d1d418eSSumit Saxena 	if (sc->facts.max_op_reply_q < sc->num_queues) {
2630*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
2631*2d1d418eSSumit Saxena 		    "Cannot reduce number of operational reply queues from %d to %d\n",
2632*2d1d418eSSumit Saxena 		    sc->num_queues,
2633*2d1d418eSSumit Saxena 		    sc->facts.max_op_reply_q);
2634*2d1d418eSSumit Saxena 		return -EPERM;
2635*2d1d418eSSumit Saxena 	}
2636*2d1d418eSSumit Saxena 
2637*2d1d418eSSumit Saxena 	if (sc->facts.max_op_req_q < sc->num_queues) {
2638*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
2639*2d1d418eSSumit Saxena 		    "Cannot reduce number of operational request queues from %d to %d\n",
2640*2d1d418eSSumit Saxena 		    sc->num_queues, sc->facts.max_op_req_q);
2641*2d1d418eSSumit Saxena 		return -EPERM;
2642*2d1d418eSSumit Saxena 	}
2643*2d1d418eSSumit Saxena 
2644*2d1d418eSSumit Saxena 	dev_handle_bitmap_sz = MPI3MR_DIV_ROUND_UP(sc->facts.max_devhandle, 8);
2645*2d1d418eSSumit Saxena 
2646*2d1d418eSSumit Saxena 	if (dev_handle_bitmap_sz > sc->dev_handle_bitmap_sz) {
2647*2d1d418eSSumit Saxena 		removepend_bitmap = realloc(sc->removepend_bitmap,
2648*2d1d418eSSumit Saxena 		    dev_handle_bitmap_sz, M_MPI3MR, M_NOWAIT);
2649*2d1d418eSSumit Saxena 
2650*2d1d418eSSumit Saxena 		if (!removepend_bitmap) {
2651*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
2652*2d1d418eSSumit Saxena 			    "failed to increase removepend_bitmap sz from: %d to %d\n",
2653*2d1d418eSSumit Saxena 			    sc->dev_handle_bitmap_sz, dev_handle_bitmap_sz);
2654*2d1d418eSSumit Saxena 			return -ENOMEM;
2655*2d1d418eSSumit Saxena 		}
2656*2d1d418eSSumit Saxena 
2657*2d1d418eSSumit Saxena 		memset(removepend_bitmap + sc->dev_handle_bitmap_sz, 0,
2658*2d1d418eSSumit Saxena 		    dev_handle_bitmap_sz - sc->dev_handle_bitmap_sz);
2659*2d1d418eSSumit Saxena 		sc->removepend_bitmap = removepend_bitmap;
2660*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
2661*2d1d418eSSumit Saxena 		    "increased dev_handle_bitmap_sz from %d to %d\n",
2662*2d1d418eSSumit Saxena 		    sc->dev_handle_bitmap_sz, dev_handle_bitmap_sz);
2663*2d1d418eSSumit Saxena 		sc->dev_handle_bitmap_sz = dev_handle_bitmap_sz;
2664*2d1d418eSSumit Saxena 	}
2665*2d1d418eSSumit Saxena 
2666*2d1d418eSSumit Saxena 	return 0;
2667*2d1d418eSSumit Saxena }
2668*2d1d418eSSumit Saxena 
2669*2d1d418eSSumit Saxena /*
2670*2d1d418eSSumit Saxena  * mpi3mr_initialize_ioc - Controller initialization
2671*2d1d418eSSumit Saxena  * @dev: pointer to device struct
2672*2d1d418eSSumit Saxena  *
2673*2d1d418eSSumit Saxena  * This function allocates the controller wide resources and brings
2674*2d1d418eSSumit Saxena  * the controller to operational state
2675*2d1d418eSSumit Saxena  *
2676*2d1d418eSSumit Saxena  * Return: 0 on success and proper error codes on failure
2677*2d1d418eSSumit Saxena  */
2678*2d1d418eSSumit Saxena int mpi3mr_initialize_ioc(struct mpi3mr_softc *sc, U8 init_type)
2679*2d1d418eSSumit Saxena {
2680*2d1d418eSSumit Saxena 	int retval = 0;
2681*2d1d418eSSumit Saxena 	enum mpi3mr_iocstate ioc_state;
2682*2d1d418eSSumit Saxena 	U64 ioc_info;
2683*2d1d418eSSumit Saxena 	U32 ioc_status, ioc_control, i, timeout;
2684*2d1d418eSSumit Saxena 	Mpi3IOCFactsData_t facts_data;
2685*2d1d418eSSumit Saxena 	char str[32];
2686*2d1d418eSSumit Saxena 	U32 size;
2687*2d1d418eSSumit Saxena 
2688*2d1d418eSSumit Saxena 	sc->cpu_count = mp_ncpus;
2689*2d1d418eSSumit Saxena 
2690*2d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
2691*2d1d418eSSumit Saxena 	ioc_control = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
2692*2d1d418eSSumit Saxena 	ioc_info = mpi3mr_regread64(sc, MPI3_SYSIF_IOC_INFO_LOW_OFFSET);
2693*2d1d418eSSumit Saxena 
2694*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "SOD ioc_status: 0x%x ioc_control: 0x%x "
2695*2d1d418eSSumit Saxena 	    "ioc_info: 0x%lx\n", ioc_status, ioc_control, ioc_info);
2696*2d1d418eSSumit Saxena 
2697*2d1d418eSSumit Saxena         /*The timeout value is in 2sec unit, changing it to seconds*/
2698*2d1d418eSSumit Saxena 	sc->ready_timeout =
2699*2d1d418eSSumit Saxena                 ((ioc_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
2700*2d1d418eSSumit Saxena                     MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
2701*2d1d418eSSumit Saxena 
2702*2d1d418eSSumit Saxena 	ioc_state = mpi3mr_get_iocstate(sc);
2703*2d1d418eSSumit Saxena 
2704*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "IOC state: %s   IOC ready timeout: %d\n",
2705*2d1d418eSSumit Saxena 	    mpi3mr_iocstate_name(ioc_state), sc->ready_timeout);
2706*2d1d418eSSumit Saxena 
2707*2d1d418eSSumit Saxena 	if (ioc_state == MRIOC_STATE_BECOMING_READY ||
2708*2d1d418eSSumit Saxena 	    ioc_state == MRIOC_STATE_RESET_REQUESTED) {
2709*2d1d418eSSumit Saxena 		timeout = sc->ready_timeout * 10;
2710*2d1d418eSSumit Saxena 		do {
2711*2d1d418eSSumit Saxena 			DELAY(1000 * 100);
2712*2d1d418eSSumit Saxena 		} while (--timeout);
2713*2d1d418eSSumit Saxena 
2714*2d1d418eSSumit Saxena 		ioc_state = mpi3mr_get_iocstate(sc);
2715*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
2716*2d1d418eSSumit Saxena 			"IOC in %s state after waiting for reset time\n",
2717*2d1d418eSSumit Saxena 			mpi3mr_iocstate_name(ioc_state));
2718*2d1d418eSSumit Saxena 	}
2719*2d1d418eSSumit Saxena 
2720*2d1d418eSSumit Saxena 	if (ioc_state == MRIOC_STATE_READY) {
2721*2d1d418eSSumit Saxena                 retval = mpi3mr_mur_ioc(sc, MPI3MR_RESET_FROM_BRINGUP);
2722*2d1d418eSSumit Saxena                 if (retval) {
2723*2d1d418eSSumit Saxena                         mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to MU reset IOC, error 0x%x\n",
2724*2d1d418eSSumit Saxena                                 retval);
2725*2d1d418eSSumit Saxena                 }
2726*2d1d418eSSumit Saxena                 ioc_state = mpi3mr_get_iocstate(sc);
2727*2d1d418eSSumit Saxena         }
2728*2d1d418eSSumit Saxena 
2729*2d1d418eSSumit Saxena         if (ioc_state != MRIOC_STATE_RESET) {
2730*2d1d418eSSumit Saxena                 mpi3mr_print_fault_info(sc);
2731*2d1d418eSSumit Saxena 		 mpi3mr_dprint(sc, MPI3MR_ERROR, "issuing soft reset to bring to reset state\n");
2732*2d1d418eSSumit Saxena                  retval = mpi3mr_issue_reset(sc,
2733*2d1d418eSSumit Saxena                      MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
2734*2d1d418eSSumit Saxena                      MPI3MR_RESET_FROM_BRINGUP);
2735*2d1d418eSSumit Saxena                 if (retval) {
2736*2d1d418eSSumit Saxena                         mpi3mr_dprint(sc, MPI3MR_ERROR,
2737*2d1d418eSSumit Saxena                             "%s :Failed to soft reset IOC, error 0x%d\n",
2738*2d1d418eSSumit Saxena                             __func__, retval);
2739*2d1d418eSSumit Saxena                         goto out_failed;
2740*2d1d418eSSumit Saxena                 }
2741*2d1d418eSSumit Saxena         }
2742*2d1d418eSSumit Saxena 
2743*2d1d418eSSumit Saxena 	ioc_state = mpi3mr_get_iocstate(sc);
2744*2d1d418eSSumit Saxena 
2745*2d1d418eSSumit Saxena         if (ioc_state != MRIOC_STATE_RESET) {
2746*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot bring IOC to reset state\n");
2747*2d1d418eSSumit Saxena 		goto out_failed;
2748*2d1d418eSSumit Saxena         }
2749*2d1d418eSSumit Saxena 
2750*2d1d418eSSumit Saxena 	retval = mpi3mr_setup_admin_qpair(sc);
2751*2d1d418eSSumit Saxena 	if (retval) {
2752*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to setup Admin queues, error 0x%x\n",
2753*2d1d418eSSumit Saxena 		    retval);
2754*2d1d418eSSumit Saxena 		goto out_failed;
2755*2d1d418eSSumit Saxena 	}
2756*2d1d418eSSumit Saxena 
2757*2d1d418eSSumit Saxena 	retval = mpi3mr_bring_ioc_ready(sc);
2758*2d1d418eSSumit Saxena 	if (retval) {
2759*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to bring IOC ready, error 0x%x\n",
2760*2d1d418eSSumit Saxena 		    retval);
2761*2d1d418eSSumit Saxena 		goto out_failed;
2762*2d1d418eSSumit Saxena 	}
2763*2d1d418eSSumit Saxena 
2764*2d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_INIT) {
2765*2d1d418eSSumit Saxena 		retval = mpi3mr_alloc_interrupts(sc, 1);
2766*2d1d418eSSumit Saxena 		if (retval) {
2767*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate interrupts, error 0x%x\n",
2768*2d1d418eSSumit Saxena 			    retval);
2769*2d1d418eSSumit Saxena 			goto out_failed;
2770*2d1d418eSSumit Saxena 		}
2771*2d1d418eSSumit Saxena 
2772*2d1d418eSSumit Saxena 		retval = mpi3mr_setup_irqs(sc);
2773*2d1d418eSSumit Saxena 		if (retval) {
2774*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to setup ISR, error 0x%x\n",
2775*2d1d418eSSumit Saxena 			    retval);
2776*2d1d418eSSumit Saxena 			goto out_failed;
2777*2d1d418eSSumit Saxena 		}
2778*2d1d418eSSumit Saxena 	}
2779*2d1d418eSSumit Saxena 
2780*2d1d418eSSumit Saxena 	mpi3mr_enable_interrupts(sc);
2781*2d1d418eSSumit Saxena 
2782*2d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_INIT) {
2783*2d1d418eSSumit Saxena 		mtx_init(&sc->mpi3mr_mtx, "SIM lock", NULL, MTX_DEF);
2784*2d1d418eSSumit Saxena 		mtx_init(&sc->io_lock, "IO lock", NULL, MTX_DEF);
2785*2d1d418eSSumit Saxena 		mtx_init(&sc->admin_req_lock, "Admin Request Queue lock", NULL, MTX_SPIN);
2786*2d1d418eSSumit Saxena 		mtx_init(&sc->reply_free_q_lock, "Reply free Queue lock", NULL, MTX_SPIN);
2787*2d1d418eSSumit Saxena 		mtx_init(&sc->sense_buf_q_lock, "Sense buffer Queue lock", NULL, MTX_SPIN);
2788*2d1d418eSSumit Saxena 		mtx_init(&sc->chain_buf_lock, "Chain buffer lock", NULL, MTX_SPIN);
2789*2d1d418eSSumit Saxena 		mtx_init(&sc->cmd_pool_lock, "Command pool lock", NULL, MTX_DEF);
2790*2d1d418eSSumit Saxena //		mtx_init(&sc->fwevt_lock, "Firmware Event lock", NULL, MTX_SPIN);
2791*2d1d418eSSumit Saxena 		mtx_init(&sc->fwevt_lock, "Firmware Event lock", NULL, MTX_DEF);
2792*2d1d418eSSumit Saxena 		mtx_init(&sc->target_lock, "Target lock", NULL, MTX_SPIN);
2793*2d1d418eSSumit Saxena 		mtx_init(&sc->reset_mutex, "Reset lock", NULL, MTX_DEF);
2794*2d1d418eSSumit Saxena 
2795*2d1d418eSSumit Saxena 		mtx_init(&sc->init_cmds.completion.lock, "Init commands lock", NULL, MTX_DEF);
2796*2d1d418eSSumit Saxena 		sc->init_cmds.reply = NULL;
2797*2d1d418eSSumit Saxena 		sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
2798*2d1d418eSSumit Saxena 		sc->init_cmds.dev_handle = MPI3MR_INVALID_DEV_HANDLE;
2799*2d1d418eSSumit Saxena 		sc->init_cmds.host_tag = MPI3MR_HOSTTAG_INITCMDS;
2800*2d1d418eSSumit Saxena 
2801*2d1d418eSSumit Saxena 		mtx_init(&sc->ioctl_cmds.completion.lock, "IOCTL commands lock", NULL, MTX_DEF);
2802*2d1d418eSSumit Saxena 		sc->ioctl_cmds.reply = NULL;
2803*2d1d418eSSumit Saxena 		sc->ioctl_cmds.state = MPI3MR_CMD_NOTUSED;
2804*2d1d418eSSumit Saxena 		sc->ioctl_cmds.dev_handle = MPI3MR_INVALID_DEV_HANDLE;
2805*2d1d418eSSumit Saxena 		sc->ioctl_cmds.host_tag = MPI3MR_HOSTTAG_IOCTLCMDS;
2806*2d1d418eSSumit Saxena 
2807*2d1d418eSSumit Saxena 		mtx_init(&sc->pel_abort_cmd.completion.lock, "PEL Abort command lock", NULL, MTX_DEF);
2808*2d1d418eSSumit Saxena 		sc->pel_abort_cmd.reply = NULL;
2809*2d1d418eSSumit Saxena 		sc->pel_abort_cmd.state = MPI3MR_CMD_NOTUSED;
2810*2d1d418eSSumit Saxena 		sc->pel_abort_cmd.dev_handle = MPI3MR_INVALID_DEV_HANDLE;
2811*2d1d418eSSumit Saxena 		sc->pel_abort_cmd.host_tag = MPI3MR_HOSTTAG_PELABORT;
2812*2d1d418eSSumit Saxena 
2813*2d1d418eSSumit Saxena 		mtx_init(&sc->host_tm_cmds.completion.lock, "TM commands lock", NULL, MTX_DEF);
2814*2d1d418eSSumit Saxena 		sc->host_tm_cmds.reply = NULL;
2815*2d1d418eSSumit Saxena 		sc->host_tm_cmds.state = MPI3MR_CMD_NOTUSED;
2816*2d1d418eSSumit Saxena 		sc->host_tm_cmds.dev_handle = MPI3MR_INVALID_DEV_HANDLE;
2817*2d1d418eSSumit Saxena 		sc->host_tm_cmds.host_tag = MPI3MR_HOSTTAG_TMS;
2818*2d1d418eSSumit Saxena 
2819*2d1d418eSSumit Saxena 		TAILQ_INIT(&sc->cmd_list_head);
2820*2d1d418eSSumit Saxena 		TAILQ_INIT(&sc->event_list);
2821*2d1d418eSSumit Saxena 		TAILQ_INIT(&sc->delayed_rmhs_list);
2822*2d1d418eSSumit Saxena 		TAILQ_INIT(&sc->delayed_evtack_cmds_list);
2823*2d1d418eSSumit Saxena 
2824*2d1d418eSSumit Saxena 		for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
2825*2d1d418eSSumit Saxena 			snprintf(str, 32, "Dev REMHS commands lock[%d]", i);
2826*2d1d418eSSumit Saxena 			mtx_init(&sc->dev_rmhs_cmds[i].completion.lock, str, NULL, MTX_DEF);
2827*2d1d418eSSumit Saxena 			sc->dev_rmhs_cmds[i].reply = NULL;
2828*2d1d418eSSumit Saxena 			sc->dev_rmhs_cmds[i].state = MPI3MR_CMD_NOTUSED;
2829*2d1d418eSSumit Saxena 			sc->dev_rmhs_cmds[i].dev_handle = MPI3MR_INVALID_DEV_HANDLE;
2830*2d1d418eSSumit Saxena 			sc->dev_rmhs_cmds[i].host_tag = MPI3MR_HOSTTAG_DEVRMCMD_MIN
2831*2d1d418eSSumit Saxena 							    + i;
2832*2d1d418eSSumit Saxena 		}
2833*2d1d418eSSumit Saxena 	}
2834*2d1d418eSSumit Saxena 
2835*2d1d418eSSumit Saxena 	retval = mpi3mr_issue_iocfacts(sc, &facts_data);
2836*2d1d418eSSumit Saxena 	if (retval) {
2837*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to Issue IOC Facts, retval: 0x%x\n",
2838*2d1d418eSSumit Saxena 		    retval);
2839*2d1d418eSSumit Saxena 		goto out_failed;
2840*2d1d418eSSumit Saxena 	}
2841*2d1d418eSSumit Saxena 
2842*2d1d418eSSumit Saxena 	retval = mpi3mr_process_factsdata(sc, &facts_data);
2843*2d1d418eSSumit Saxena 	if (retval) {
2844*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "IOC Facts data processing failedi, retval: 0x%x\n",
2845*2d1d418eSSumit Saxena 		    retval);
2846*2d1d418eSSumit Saxena 		goto out_failed;
2847*2d1d418eSSumit Saxena 	}
2848*2d1d418eSSumit Saxena 
2849*2d1d418eSSumit Saxena 	sc->num_io_throttle_group = sc->facts.max_io_throttle_group;
2850*2d1d418eSSumit Saxena 	mpi3mr_atomic_set(&sc->pend_large_data_sz, 0);
2851*2d1d418eSSumit Saxena 
2852*2d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_RESET) {
2853*2d1d418eSSumit Saxena 		retval = mpi3mr_validate_fw_update(sc);
2854*2d1d418eSSumit Saxena 		if (retval)
2855*2d1d418eSSumit Saxena 			goto out_failed;
2856*2d1d418eSSumit Saxena 	} else {
2857*2d1d418eSSumit Saxena 		sc->reply_sz = sc->facts.reply_sz;
2858*2d1d418eSSumit Saxena 	}
2859*2d1d418eSSumit Saxena 
2860*2d1d418eSSumit Saxena 
2861*2d1d418eSSumit Saxena 	mpi3mr_display_ioc_info(sc);
2862*2d1d418eSSumit Saxena 
2863*2d1d418eSSumit Saxena 	retval = mpi3mr_reply_alloc(sc);
2864*2d1d418eSSumit Saxena 	if (retval) {
2865*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocated reply and sense buffers, retval: 0x%x\n",
2866*2d1d418eSSumit Saxena 		    retval);
2867*2d1d418eSSumit Saxena 		goto out_failed;
2868*2d1d418eSSumit Saxena 	}
2869*2d1d418eSSumit Saxena 
2870*2d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_INIT) {
2871*2d1d418eSSumit Saxena 		retval = mpi3mr_alloc_chain_bufs(sc);
2872*2d1d418eSSumit Saxena 		if (retval) {
2873*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocated chain buffers, retval: 0x%x\n",
2874*2d1d418eSSumit Saxena 			    retval);
2875*2d1d418eSSumit Saxena 			goto out_failed;
2876*2d1d418eSSumit Saxena 		}
2877*2d1d418eSSumit Saxena 	}
2878*2d1d418eSSumit Saxena 
2879*2d1d418eSSumit Saxena 	retval = mpi3mr_issue_iocinit(sc);
2880*2d1d418eSSumit Saxena 	if (retval) {
2881*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to Issue IOC Init, retval: 0x%x\n",
2882*2d1d418eSSumit Saxena 		    retval);
2883*2d1d418eSSumit Saxena 		goto out_failed;
2884*2d1d418eSSumit Saxena 	}
2885*2d1d418eSSumit Saxena 
2886*2d1d418eSSumit Saxena 	mpi3mr_print_fw_pkg_ver(sc);
2887*2d1d418eSSumit Saxena 
2888*2d1d418eSSumit Saxena 	sc->reply_free_q_host_index = sc->num_reply_bufs;
2889*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_REPLY_FREE_HOST_INDEX_OFFSET,
2890*2d1d418eSSumit Saxena 		sc->reply_free_q_host_index);
2891*2d1d418eSSumit Saxena 
2892*2d1d418eSSumit Saxena 	sc->sense_buf_q_host_index = sc->num_sense_bufs;
2893*2d1d418eSSumit Saxena 
2894*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_SENSE_BUF_FREE_HOST_INDEX_OFFSET,
2895*2d1d418eSSumit Saxena 		sc->sense_buf_q_host_index);
2896*2d1d418eSSumit Saxena 
2897*2d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_INIT) {
2898*2d1d418eSSumit Saxena 		retval = mpi3mr_alloc_interrupts(sc, 0);
2899*2d1d418eSSumit Saxena 		if (retval) {
2900*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate interrupts, retval: 0x%x\n",
2901*2d1d418eSSumit Saxena 			    retval);
2902*2d1d418eSSumit Saxena 			goto out_failed;
2903*2d1d418eSSumit Saxena 		}
2904*2d1d418eSSumit Saxena 
2905*2d1d418eSSumit Saxena 		retval = mpi3mr_setup_irqs(sc);
2906*2d1d418eSSumit Saxena 		if (retval) {
2907*2d1d418eSSumit Saxena 			printf(IOCNAME "Failed to setup ISR, error: 0x%x\n",
2908*2d1d418eSSumit Saxena 			    sc->name, retval);
2909*2d1d418eSSumit Saxena 			goto out_failed;
2910*2d1d418eSSumit Saxena 		}
2911*2d1d418eSSumit Saxena 
2912*2d1d418eSSumit Saxena 		mpi3mr_enable_interrupts(sc);
2913*2d1d418eSSumit Saxena 
2914*2d1d418eSSumit Saxena 	} else
2915*2d1d418eSSumit Saxena 		mpi3mr_enable_interrupts(sc);
2916*2d1d418eSSumit Saxena 
2917*2d1d418eSSumit Saxena 	retval = mpi3mr_create_op_queues(sc);
2918*2d1d418eSSumit Saxena 
2919*2d1d418eSSumit Saxena 	if (retval) {
2920*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to create operational queues, error: %d\n",
2921*2d1d418eSSumit Saxena 		    retval);
2922*2d1d418eSSumit Saxena 		goto out_failed;
2923*2d1d418eSSumit Saxena 	}
2924*2d1d418eSSumit Saxena 
2925*2d1d418eSSumit Saxena 	if (!sc->throttle_groups && sc->num_io_throttle_group) {
2926*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "allocating memory for throttle groups\n");
2927*2d1d418eSSumit Saxena 		size = sizeof(struct mpi3mr_throttle_group_info);
2928*2d1d418eSSumit Saxena 		sc->throttle_groups = (struct mpi3mr_throttle_group_info *)
2929*2d1d418eSSumit Saxena 					  malloc(sc->num_io_throttle_group *
2930*2d1d418eSSumit Saxena 					      size, M_MPI3MR, M_NOWAIT | M_ZERO);
2931*2d1d418eSSumit Saxena 		if (!sc->throttle_groups)
2932*2d1d418eSSumit Saxena 			goto out_failed;
2933*2d1d418eSSumit Saxena 	}
2934*2d1d418eSSumit Saxena 
2935*2d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_RESET) {
2936*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "Re-register events\n");
2937*2d1d418eSSumit Saxena 		retval = mpi3mr_register_events(sc);
2938*2d1d418eSSumit Saxena 		if (retval) {
2939*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO, "Failed to re-register events, retval: 0x%x\n",
2940*2d1d418eSSumit Saxena 			    retval);
2941*2d1d418eSSumit Saxena 			goto out_failed;
2942*2d1d418eSSumit Saxena 		}
2943*2d1d418eSSumit Saxena 
2944*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "Issuing Port Enable\n");
2945*2d1d418eSSumit Saxena 		retval = mpi3mr_issue_port_enable(sc, 0);
2946*2d1d418eSSumit Saxena 		if (retval) {
2947*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO, "Failed to issue port enable, retval: 0x%x\n",
2948*2d1d418eSSumit Saxena 			    retval);
2949*2d1d418eSSumit Saxena 			goto out_failed;
2950*2d1d418eSSumit Saxena 		}
2951*2d1d418eSSumit Saxena 	}
2952*2d1d418eSSumit Saxena 	retval = mpi3mr_pel_alloc(sc);
2953*2d1d418eSSumit Saxena 	if (retval) {
2954*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate memory for PEL, retval: 0x%x\n",
2955*2d1d418eSSumit Saxena 		    retval);
2956*2d1d418eSSumit Saxena 		goto out_failed;
2957*2d1d418eSSumit Saxena 	}
2958*2d1d418eSSumit Saxena 
2959*2d1d418eSSumit Saxena 	return retval;
2960*2d1d418eSSumit Saxena 
2961*2d1d418eSSumit Saxena out_failed:
2962*2d1d418eSSumit Saxena 	retval = -1;
2963*2d1d418eSSumit Saxena 	return retval;
2964*2d1d418eSSumit Saxena }
2965*2d1d418eSSumit Saxena 
2966*2d1d418eSSumit Saxena static void mpi3mr_port_enable_complete(struct mpi3mr_softc *sc,
2967*2d1d418eSSumit Saxena     struct mpi3mr_drvr_cmd *drvrcmd)
2968*2d1d418eSSumit Saxena {
2969*2d1d418eSSumit Saxena 	drvrcmd->state = MPI3MR_CMD_NOTUSED;
2970*2d1d418eSSumit Saxena 	drvrcmd->callback = NULL;
2971*2d1d418eSSumit Saxena 	printf(IOCNAME "Completing Port Enable Request\n", sc->name);
2972*2d1d418eSSumit Saxena 	sc->mpi3mr_flags |= MPI3MR_FLAGS_PORT_ENABLE_DONE;
2973*2d1d418eSSumit Saxena 	mpi3mr_startup_decrement(sc->cam_sc);
2974*2d1d418eSSumit Saxena }
2975*2d1d418eSSumit Saxena 
2976*2d1d418eSSumit Saxena int mpi3mr_issue_port_enable(struct mpi3mr_softc *sc, U8 async)
2977*2d1d418eSSumit Saxena {
2978*2d1d418eSSumit Saxena 	Mpi3PortEnableRequest_t pe_req;
2979*2d1d418eSSumit Saxena 	int retval = 0;
2980*2d1d418eSSumit Saxena 
2981*2d1d418eSSumit Saxena 	memset(&pe_req, 0, sizeof(pe_req));
2982*2d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
2983*2d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
2984*2d1d418eSSumit Saxena 		retval = -1;
2985*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue PortEnable: Init command is in use\n", sc->name);
2986*2d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
2987*2d1d418eSSumit Saxena 		goto out;
2988*2d1d418eSSumit Saxena 	}
2989*2d1d418eSSumit Saxena 
2990*2d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
2991*2d1d418eSSumit Saxena 
2992*2d1d418eSSumit Saxena 	if (async) {
2993*2d1d418eSSumit Saxena 		sc->init_cmds.is_waiting = 0;
2994*2d1d418eSSumit Saxena 		sc->init_cmds.callback = mpi3mr_port_enable_complete;
2995*2d1d418eSSumit Saxena 	} else {
2996*2d1d418eSSumit Saxena 		sc->init_cmds.is_waiting = 1;
2997*2d1d418eSSumit Saxena 		sc->init_cmds.callback = NULL;
2998*2d1d418eSSumit Saxena 		init_completion(&sc->init_cmds.completion);
2999*2d1d418eSSumit Saxena 	}
3000*2d1d418eSSumit Saxena 	pe_req.HostTag = MPI3MR_HOSTTAG_INITCMDS;
3001*2d1d418eSSumit Saxena 	pe_req.Function = MPI3_FUNCTION_PORT_ENABLE;
3002*2d1d418eSSumit Saxena 
3003*2d1d418eSSumit Saxena 	printf(IOCNAME "Sending Port Enable Request\n", sc->name);
3004*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &pe_req, sizeof(pe_req));
3005*2d1d418eSSumit Saxena 	if (retval) {
3006*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue PortEnable: Admin Post failed\n",
3007*2d1d418eSSumit Saxena 		    sc->name);
3008*2d1d418eSSumit Saxena 		goto out_unlock;
3009*2d1d418eSSumit Saxena 	}
3010*2d1d418eSSumit Saxena 
3011*2d1d418eSSumit Saxena 	if (!async) {
3012*2d1d418eSSumit Saxena 		wait_for_completion_timeout(&sc->init_cmds.completion,
3013*2d1d418eSSumit Saxena 		    MPI3MR_PORTENABLE_TIMEOUT);
3014*2d1d418eSSumit Saxena 		if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
3015*2d1d418eSSumit Saxena 			printf(IOCNAME "Issue PortEnable: command timed out\n",
3016*2d1d418eSSumit Saxena 			    sc->name);
3017*2d1d418eSSumit Saxena 			retval = -1;
3018*2d1d418eSSumit Saxena 			mpi3mr_check_rh_fault_ioc(sc, MPI3MR_RESET_FROM_PE_TIMEOUT);
3019*2d1d418eSSumit Saxena 			goto out_unlock;
3020*2d1d418eSSumit Saxena 		}
3021*2d1d418eSSumit Saxena 		mpi3mr_port_enable_complete(sc, &sc->init_cmds);
3022*2d1d418eSSumit Saxena 	}
3023*2d1d418eSSumit Saxena out_unlock:
3024*2d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
3025*2d1d418eSSumit Saxena 
3026*2d1d418eSSumit Saxena out:
3027*2d1d418eSSumit Saxena 	return retval;
3028*2d1d418eSSumit Saxena }
3029*2d1d418eSSumit Saxena 
3030*2d1d418eSSumit Saxena void
3031*2d1d418eSSumit Saxena mpi3mr_watchdog_thread(void *arg)
3032*2d1d418eSSumit Saxena {
3033*2d1d418eSSumit Saxena 	struct mpi3mr_softc *sc;
3034*2d1d418eSSumit Saxena 	enum mpi3mr_iocstate ioc_state;
3035*2d1d418eSSumit Saxena 	U32 fault, host_diagnostic, ioc_status;
3036*2d1d418eSSumit Saxena 
3037*2d1d418eSSumit Saxena 	sc = (struct mpi3mr_softc *)arg;
3038*2d1d418eSSumit Saxena 
3039*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "%s\n", __func__);
3040*2d1d418eSSumit Saxena 
3041*2d1d418eSSumit Saxena 	sc->watchdog_thread_active = 1;
3042*2d1d418eSSumit Saxena 	mtx_lock(&sc->reset_mutex);
3043*2d1d418eSSumit Saxena 	for (;;) {
3044*2d1d418eSSumit Saxena 		/* Sleep for 1 second and check the queue status */
3045*2d1d418eSSumit Saxena 		msleep(&sc->watchdog_chan, &sc->reset_mutex, PRIBIO,
3046*2d1d418eSSumit Saxena 		    "mpi3mr_watchdog", 1 * hz);
3047*2d1d418eSSumit Saxena 		if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN ||
3048*2d1d418eSSumit Saxena 		    (sc->unrecoverable == 1)) {
3049*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO,
3050*2d1d418eSSumit Saxena 			    "Exit due to %s from %s\n",
3051*2d1d418eSSumit Saxena 			   sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN ? "Shutdown" :
3052*2d1d418eSSumit Saxena 			    "Hardware critical error", __func__);
3053*2d1d418eSSumit Saxena 			break;
3054*2d1d418eSSumit Saxena 		}
3055*2d1d418eSSumit Saxena 
3056*2d1d418eSSumit Saxena 		if ((sc->prepare_for_reset) &&
3057*2d1d418eSSumit Saxena 		    ((sc->prepare_for_reset_timeout_counter++) >=
3058*2d1d418eSSumit Saxena 		     MPI3MR_PREPARE_FOR_RESET_TIMEOUT)) {
3059*2d1d418eSSumit Saxena 			mpi3mr_soft_reset_handler(sc,
3060*2d1d418eSSumit Saxena 			    MPI3MR_RESET_FROM_CIACTVRST_TIMER, 1);
3061*2d1d418eSSumit Saxena 			continue;
3062*2d1d418eSSumit Saxena 		}
3063*2d1d418eSSumit Saxena 
3064*2d1d418eSSumit Saxena 		ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
3065*2d1d418eSSumit Saxena 
3066*2d1d418eSSumit Saxena 		if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
3067*2d1d418eSSumit Saxena 			mpi3mr_soft_reset_handler(sc, MPI3MR_RESET_FROM_FIRMWARE, 0);
3068*2d1d418eSSumit Saxena 			continue;
3069*2d1d418eSSumit Saxena 		}
3070*2d1d418eSSumit Saxena 
3071*2d1d418eSSumit Saxena 		ioc_state = mpi3mr_get_iocstate(sc);
3072*2d1d418eSSumit Saxena 		if (ioc_state == MRIOC_STATE_FAULT) {
3073*2d1d418eSSumit Saxena 			fault = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_OFFSET) &
3074*2d1d418eSSumit Saxena 			    MPI3_SYSIF_FAULT_CODE_MASK;
3075*2d1d418eSSumit Saxena 
3076*2d1d418eSSumit Saxena 			host_diagnostic = mpi3mr_regread(sc, MPI3_SYSIF_HOST_DIAG_OFFSET);
3077*2d1d418eSSumit Saxena 			if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) {
3078*2d1d418eSSumit Saxena 				if (!sc->diagsave_timeout) {
3079*2d1d418eSSumit Saxena 					mpi3mr_print_fault_info(sc);
3080*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_INFO,
3081*2d1d418eSSumit Saxena 						"diag save in progress\n");
3082*2d1d418eSSumit Saxena 				}
3083*2d1d418eSSumit Saxena 				if ((sc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT)
3084*2d1d418eSSumit Saxena 					continue;
3085*2d1d418eSSumit Saxena 			}
3086*2d1d418eSSumit Saxena 			mpi3mr_print_fault_info(sc);
3087*2d1d418eSSumit Saxena 			sc->diagsave_timeout = 0;
3088*2d1d418eSSumit Saxena 
3089*2d1d418eSSumit Saxena 			if ((fault == MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED) ||
3090*2d1d418eSSumit Saxena 			    (fault == MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED)) {
3091*2d1d418eSSumit Saxena 				mpi3mr_dprint(sc, MPI3MR_INFO,
3092*2d1d418eSSumit Saxena 				    "Controller requires system power cycle or complete reset is needed,"
3093*2d1d418eSSumit Saxena 				    "fault code: 0x%x. marking controller as unrecoverable\n", fault);
3094*2d1d418eSSumit Saxena 				sc->unrecoverable = 1;
3095*2d1d418eSSumit Saxena 				goto out;
3096*2d1d418eSSumit Saxena 			}
3097*2d1d418eSSumit Saxena 			if ((fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET)
3098*2d1d418eSSumit Saxena 			    || (fault == MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS)
3099*2d1d418eSSumit Saxena 			    || (sc->reset_in_progress))
3100*2d1d418eSSumit Saxena 				goto out;
3101*2d1d418eSSumit Saxena 			if (fault == MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET)
3102*2d1d418eSSumit Saxena 				mpi3mr_soft_reset_handler(sc,
3103*2d1d418eSSumit Saxena 				    MPI3MR_RESET_FROM_CIACTIV_FAULT, 0);
3104*2d1d418eSSumit Saxena 			else
3105*2d1d418eSSumit Saxena 				mpi3mr_soft_reset_handler(sc,
3106*2d1d418eSSumit Saxena 				    MPI3MR_RESET_FROM_FAULT_WATCH, 0);
3107*2d1d418eSSumit Saxena 
3108*2d1d418eSSumit Saxena 		}
3109*2d1d418eSSumit Saxena 
3110*2d1d418eSSumit Saxena 		if (sc->reset.type == MPI3MR_TRIGGER_SOFT_RESET) {
3111*2d1d418eSSumit Saxena 			mpi3mr_print_fault_info(sc);
3112*2d1d418eSSumit Saxena 			mpi3mr_soft_reset_handler(sc, sc->reset.reason, 1);
3113*2d1d418eSSumit Saxena 		}
3114*2d1d418eSSumit Saxena 	}
3115*2d1d418eSSumit Saxena out:
3116*2d1d418eSSumit Saxena 	mtx_unlock(&sc->reset_mutex);
3117*2d1d418eSSumit Saxena 	sc->watchdog_thread_active = 0;
3118*2d1d418eSSumit Saxena 	mpi3mr_kproc_exit(0);
3119*2d1d418eSSumit Saxena }
3120*2d1d418eSSumit Saxena 
3121*2d1d418eSSumit Saxena static void mpi3mr_display_event_data(struct mpi3mr_softc *sc,
3122*2d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_rep)
3123*2d1d418eSSumit Saxena {
3124*2d1d418eSSumit Saxena 	char *desc = NULL;
3125*2d1d418eSSumit Saxena 	U16 event;
3126*2d1d418eSSumit Saxena 
3127*2d1d418eSSumit Saxena 	event = event_rep->Event;
3128*2d1d418eSSumit Saxena 
3129*2d1d418eSSumit Saxena 	switch (event) {
3130*2d1d418eSSumit Saxena 	case MPI3_EVENT_LOG_DATA:
3131*2d1d418eSSumit Saxena 		desc = "Log Data";
3132*2d1d418eSSumit Saxena 		break;
3133*2d1d418eSSumit Saxena 	case MPI3_EVENT_CHANGE:
3134*2d1d418eSSumit Saxena 		desc = "Event Change";
3135*2d1d418eSSumit Saxena 		break;
3136*2d1d418eSSumit Saxena 	case MPI3_EVENT_GPIO_INTERRUPT:
3137*2d1d418eSSumit Saxena 		desc = "GPIO Interrupt";
3138*2d1d418eSSumit Saxena 		break;
3139*2d1d418eSSumit Saxena 	case MPI3_EVENT_CABLE_MGMT:
3140*2d1d418eSSumit Saxena 		desc = "Cable Management";
3141*2d1d418eSSumit Saxena 		break;
3142*2d1d418eSSumit Saxena 	case MPI3_EVENT_ENERGY_PACK_CHANGE:
3143*2d1d418eSSumit Saxena 		desc = "Energy Pack Change";
3144*2d1d418eSSumit Saxena 		break;
3145*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_ADDED:
3146*2d1d418eSSumit Saxena 	{
3147*2d1d418eSSumit Saxena 		Mpi3DevicePage0_t *event_data =
3148*2d1d418eSSumit Saxena 		    (Mpi3DevicePage0_t *)event_rep->EventData;
3149*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "Device Added: Dev=0x%04x Form=0x%x Perst id: 0x%x\n",
3150*2d1d418eSSumit Saxena 			event_data->DevHandle, event_data->DeviceForm, event_data->PersistentID);
3151*2d1d418eSSumit Saxena 		return;
3152*2d1d418eSSumit Saxena 	}
3153*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
3154*2d1d418eSSumit Saxena 	{
3155*2d1d418eSSumit Saxena 		Mpi3DevicePage0_t *event_data =
3156*2d1d418eSSumit Saxena 		    (Mpi3DevicePage0_t *)event_rep->EventData;
3157*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "Device Info Changed: Dev=0x%04x Form=0x%x\n",
3158*2d1d418eSSumit Saxena 			event_data->DevHandle, event_data->DeviceForm);
3159*2d1d418eSSumit Saxena 		return;
3160*2d1d418eSSumit Saxena 	}
3161*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
3162*2d1d418eSSumit Saxena 	{
3163*2d1d418eSSumit Saxena 		Mpi3EventDataDeviceStatusChange_t *event_data =
3164*2d1d418eSSumit Saxena 		    (Mpi3EventDataDeviceStatusChange_t *)event_rep->EventData;
3165*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "Device Status Change: Dev=0x%04x RC=0x%x\n",
3166*2d1d418eSSumit Saxena 			event_data->DevHandle, event_data->ReasonCode);
3167*2d1d418eSSumit Saxena 		return;
3168*2d1d418eSSumit Saxena 	}
3169*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_DISCOVERY:
3170*2d1d418eSSumit Saxena 	{
3171*2d1d418eSSumit Saxena 		Mpi3EventDataSasDiscovery_t *event_data =
3172*2d1d418eSSumit Saxena 		    (Mpi3EventDataSasDiscovery_t *)event_rep->EventData;
3173*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "SAS Discovery: (%s)",
3174*2d1d418eSSumit Saxena 			(event_data->ReasonCode == MPI3_EVENT_SAS_DISC_RC_STARTED) ?
3175*2d1d418eSSumit Saxena 		    "start" : "stop");
3176*2d1d418eSSumit Saxena 		if (event_data->DiscoveryStatus &&
3177*2d1d418eSSumit Saxena 		    (sc->mpi3mr_debug & MPI3MR_EVENT)) {
3178*2d1d418eSSumit Saxena 			printf("discovery_status(0x%08x)",
3179*2d1d418eSSumit Saxena 			    event_data->DiscoveryStatus);
3180*2d1d418eSSumit Saxena 
3181*2d1d418eSSumit Saxena 		}
3182*2d1d418eSSumit Saxena 
3183*2d1d418eSSumit Saxena 		if (sc->mpi3mr_debug & MPI3MR_EVENT)
3184*2d1d418eSSumit Saxena 			printf("\n");
3185*2d1d418eSSumit Saxena 		return;
3186*2d1d418eSSumit Saxena 	}
3187*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
3188*2d1d418eSSumit Saxena 		desc = "SAS Broadcast Primitive";
3189*2d1d418eSSumit Saxena 		break;
3190*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_NOTIFY_PRIMITIVE:
3191*2d1d418eSSumit Saxena 		desc = "SAS Notify Primitive";
3192*2d1d418eSSumit Saxena 		break;
3193*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
3194*2d1d418eSSumit Saxena 		desc = "SAS Init Device Status Change";
3195*2d1d418eSSumit Saxena 		break;
3196*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW:
3197*2d1d418eSSumit Saxena 		desc = "SAS Init Table Overflow";
3198*2d1d418eSSumit Saxena 		break;
3199*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
3200*2d1d418eSSumit Saxena 		desc = "SAS Topology Change List";
3201*2d1d418eSSumit Saxena 		break;
3202*2d1d418eSSumit Saxena 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
3203*2d1d418eSSumit Saxena 		desc = "Enclosure Device Status Change";
3204*2d1d418eSSumit Saxena 		break;
3205*2d1d418eSSumit Saxena 	case MPI3_EVENT_HARD_RESET_RECEIVED:
3206*2d1d418eSSumit Saxena 		desc = "Hard Reset Received";
3207*2d1d418eSSumit Saxena 		break;
3208*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_PHY_COUNTER:
3209*2d1d418eSSumit Saxena 		desc = "SAS PHY Counter";
3210*2d1d418eSSumit Saxena 		break;
3211*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
3212*2d1d418eSSumit Saxena 		desc = "SAS Device Discovery Error";
3213*2d1d418eSSumit Saxena 		break;
3214*2d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
3215*2d1d418eSSumit Saxena 		desc = "PCIE Topology Change List";
3216*2d1d418eSSumit Saxena 		break;
3217*2d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_ENUMERATION:
3218*2d1d418eSSumit Saxena 	{
3219*2d1d418eSSumit Saxena 		Mpi3EventDataPcieEnumeration_t *event_data =
3220*2d1d418eSSumit Saxena 			(Mpi3EventDataPcieEnumeration_t *)event_rep->EventData;
3221*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "PCIE Enumeration: (%s)",
3222*2d1d418eSSumit Saxena 			(event_data->ReasonCode ==
3223*2d1d418eSSumit Saxena 			    MPI3_EVENT_PCIE_ENUM_RC_STARTED) ? "start" :
3224*2d1d418eSSumit Saxena 			    "stop");
3225*2d1d418eSSumit Saxena 		if (event_data->EnumerationStatus)
3226*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_EVENT, "enumeration_status(0x%08x)",
3227*2d1d418eSSumit Saxena 			   event_data->EnumerationStatus);
3228*2d1d418eSSumit Saxena 		if (sc->mpi3mr_debug & MPI3MR_EVENT)
3229*2d1d418eSSumit Saxena 			printf("\n");
3230*2d1d418eSSumit Saxena 		return;
3231*2d1d418eSSumit Saxena 	}
3232*2d1d418eSSumit Saxena 	case MPI3_EVENT_PREPARE_FOR_RESET:
3233*2d1d418eSSumit Saxena 		desc = "Prepare For Reset";
3234*2d1d418eSSumit Saxena 		break;
3235*2d1d418eSSumit Saxena 	}
3236*2d1d418eSSumit Saxena 
3237*2d1d418eSSumit Saxena 	if (!desc)
3238*2d1d418eSSumit Saxena 		return;
3239*2d1d418eSSumit Saxena 
3240*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT, "%s\n", desc);
3241*2d1d418eSSumit Saxena }
3242*2d1d418eSSumit Saxena 
3243*2d1d418eSSumit Saxena struct mpi3mr_target *
3244*2d1d418eSSumit Saxena mpi3mr_find_target_by_per_id(struct mpi3mr_cam_softc *cam_sc,
3245*2d1d418eSSumit Saxena     uint16_t per_id)
3246*2d1d418eSSumit Saxena {
3247*2d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
3248*2d1d418eSSumit Saxena 
3249*2d1d418eSSumit Saxena 	mtx_lock_spin(&cam_sc->sc->target_lock);
3250*2d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &cam_sc->tgt_list, tgt_next) {
3251*2d1d418eSSumit Saxena 		if (target->per_id == per_id)
3252*2d1d418eSSumit Saxena 			break;
3253*2d1d418eSSumit Saxena 	}
3254*2d1d418eSSumit Saxena 
3255*2d1d418eSSumit Saxena 	mtx_unlock_spin(&cam_sc->sc->target_lock);
3256*2d1d418eSSumit Saxena 	return target;
3257*2d1d418eSSumit Saxena }
3258*2d1d418eSSumit Saxena 
3259*2d1d418eSSumit Saxena struct mpi3mr_target *
3260*2d1d418eSSumit Saxena mpi3mr_find_target_by_dev_handle(struct mpi3mr_cam_softc *cam_sc,
3261*2d1d418eSSumit Saxena     uint16_t handle)
3262*2d1d418eSSumit Saxena {
3263*2d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
3264*2d1d418eSSumit Saxena 
3265*2d1d418eSSumit Saxena 	mtx_lock_spin(&cam_sc->sc->target_lock);
3266*2d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &cam_sc->tgt_list, tgt_next) {
3267*2d1d418eSSumit Saxena 		if (target->dev_handle == handle)
3268*2d1d418eSSumit Saxena 			break;
3269*2d1d418eSSumit Saxena 
3270*2d1d418eSSumit Saxena 	}
3271*2d1d418eSSumit Saxena 	mtx_unlock_spin(&cam_sc->sc->target_lock);
3272*2d1d418eSSumit Saxena 	return target;
3273*2d1d418eSSumit Saxena }
3274*2d1d418eSSumit Saxena 
3275*2d1d418eSSumit Saxena void mpi3mr_update_device(struct mpi3mr_softc *sc,
3276*2d1d418eSSumit Saxena     struct mpi3mr_target *tgtdev, Mpi3DevicePage0_t *dev_pg0,
3277*2d1d418eSSumit Saxena     bool is_added)
3278*2d1d418eSSumit Saxena {
3279*2d1d418eSSumit Saxena 	U16 flags = 0;
3280*2d1d418eSSumit Saxena 
3281*2d1d418eSSumit Saxena 	tgtdev->per_id = (dev_pg0->PersistentID);
3282*2d1d418eSSumit Saxena 	tgtdev->dev_handle = (dev_pg0->DevHandle);
3283*2d1d418eSSumit Saxena 	tgtdev->dev_type = dev_pg0->DeviceForm;
3284*2d1d418eSSumit Saxena 	tgtdev->encl_handle = (dev_pg0->EnclosureHandle);
3285*2d1d418eSSumit Saxena 	tgtdev->parent_handle = (dev_pg0->ParentDevHandle);
3286*2d1d418eSSumit Saxena 	tgtdev->slot = (dev_pg0->Slot);
3287*2d1d418eSSumit Saxena 	tgtdev->qdepth = (dev_pg0->QueueDepth);
3288*2d1d418eSSumit Saxena 	tgtdev->wwid = (dev_pg0->WWID);
3289*2d1d418eSSumit Saxena 
3290*2d1d418eSSumit Saxena 	flags = (dev_pg0->Flags);
3291*2d1d418eSSumit Saxena 	tgtdev->is_hidden = (flags & MPI3_DEVICE0_FLAGS_HIDDEN);
3292*2d1d418eSSumit Saxena 	if (is_added == true)
3293*2d1d418eSSumit Saxena 		tgtdev->io_throttle_enabled =
3294*2d1d418eSSumit Saxena 		    (flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0;
3295*2d1d418eSSumit Saxena 
3296*2d1d418eSSumit Saxena 	switch (dev_pg0->AccessStatus) {
3297*2d1d418eSSumit Saxena 	case MPI3_DEVICE0_ASTATUS_NO_ERRORS:
3298*2d1d418eSSumit Saxena 	case MPI3_DEVICE0_ASTATUS_PREPARE:
3299*2d1d418eSSumit Saxena 	case MPI3_DEVICE0_ASTATUS_NEEDS_INITIALIZATION:
3300*2d1d418eSSumit Saxena 	case MPI3_DEVICE0_ASTATUS_DEVICE_MISSING_DELAY:
3301*2d1d418eSSumit Saxena 		break;
3302*2d1d418eSSumit Saxena 	default:
3303*2d1d418eSSumit Saxena 		tgtdev->is_hidden = 1;
3304*2d1d418eSSumit Saxena 		break;
3305*2d1d418eSSumit Saxena 	}
3306*2d1d418eSSumit Saxena 
3307*2d1d418eSSumit Saxena 	switch (tgtdev->dev_type) {
3308*2d1d418eSSumit Saxena 	case MPI3_DEVICE_DEVFORM_SAS_SATA:
3309*2d1d418eSSumit Saxena 	{
3310*2d1d418eSSumit Saxena 		Mpi3Device0SasSataFormat_t *sasinf =
3311*2d1d418eSSumit Saxena 		    &dev_pg0->DeviceSpecific.SasSataFormat;
3312*2d1d418eSSumit Saxena 		U16 dev_info = (sasinf->DeviceInfo);
3313*2d1d418eSSumit Saxena 		tgtdev->dev_spec.sassata_inf.dev_info = dev_info;
3314*2d1d418eSSumit Saxena 		tgtdev->dev_spec.sassata_inf.sas_address =
3315*2d1d418eSSumit Saxena 		    (sasinf->SASAddress);
3316*2d1d418eSSumit Saxena 		if ((dev_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) !=
3317*2d1d418eSSumit Saxena 		    MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE)
3318*2d1d418eSSumit Saxena 			tgtdev->is_hidden = 1;
3319*2d1d418eSSumit Saxena 		else if (!(dev_info & (MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET |
3320*2d1d418eSSumit Saxena 			    MPI3_SAS_DEVICE_INFO_SSP_TARGET)))
3321*2d1d418eSSumit Saxena 			tgtdev->is_hidden = 1;
3322*2d1d418eSSumit Saxena 		break;
3323*2d1d418eSSumit Saxena 	}
3324*2d1d418eSSumit Saxena 	case MPI3_DEVICE_DEVFORM_PCIE:
3325*2d1d418eSSumit Saxena 	{
3326*2d1d418eSSumit Saxena 		Mpi3Device0PcieFormat_t *pcieinf =
3327*2d1d418eSSumit Saxena 		    &dev_pg0->DeviceSpecific.PcieFormat;
3328*2d1d418eSSumit Saxena 		U16 dev_info = (pcieinf->DeviceInfo);
3329*2d1d418eSSumit Saxena 
3330*2d1d418eSSumit Saxena 		tgtdev->q_depth = dev_pg0->QueueDepth;
3331*2d1d418eSSumit Saxena 		tgtdev->dev_spec.pcie_inf.dev_info = dev_info;
3332*2d1d418eSSumit Saxena 		tgtdev->dev_spec.pcie_inf.capb =
3333*2d1d418eSSumit Saxena 		    (pcieinf->Capabilities);
3334*2d1d418eSSumit Saxena 		tgtdev->dev_spec.pcie_inf.mdts = MPI3MR_DEFAULT_MDTS;
3335*2d1d418eSSumit Saxena 		if (dev_pg0->AccessStatus == MPI3_DEVICE0_ASTATUS_NO_ERRORS) {
3336*2d1d418eSSumit Saxena 			tgtdev->dev_spec.pcie_inf.mdts =
3337*2d1d418eSSumit Saxena 			    (pcieinf->MaximumDataTransferSize);
3338*2d1d418eSSumit Saxena 			tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->PageSize;
3339*2d1d418eSSumit Saxena 			tgtdev->dev_spec.pcie_inf.reset_to =
3340*2d1d418eSSumit Saxena 				pcieinf->ControllerResetTO;
3341*2d1d418eSSumit Saxena 			tgtdev->dev_spec.pcie_inf.abort_to =
3342*2d1d418eSSumit Saxena 				pcieinf->NVMeAbortTO;
3343*2d1d418eSSumit Saxena 		}
3344*2d1d418eSSumit Saxena 		if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024))
3345*2d1d418eSSumit Saxena 			tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024);
3346*2d1d418eSSumit Saxena 
3347*2d1d418eSSumit Saxena 		if (((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
3348*2d1d418eSSumit Saxena 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) &&
3349*2d1d418eSSumit Saxena 		    ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
3350*2d1d418eSSumit Saxena 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE))
3351*2d1d418eSSumit Saxena 			tgtdev->is_hidden = 1;
3352*2d1d418eSSumit Saxena 
3353*2d1d418eSSumit Saxena 		break;
3354*2d1d418eSSumit Saxena 	}
3355*2d1d418eSSumit Saxena 	case MPI3_DEVICE_DEVFORM_VD:
3356*2d1d418eSSumit Saxena 	{
3357*2d1d418eSSumit Saxena 		Mpi3Device0VdFormat_t *vdinf =
3358*2d1d418eSSumit Saxena 		    &dev_pg0->DeviceSpecific.VdFormat;
3359*2d1d418eSSumit Saxena 		struct mpi3mr_throttle_group_info *tg = NULL;
3360*2d1d418eSSumit Saxena 
3361*2d1d418eSSumit Saxena 		tgtdev->dev_spec.vol_inf.state = vdinf->VdState;
3362*2d1d418eSSumit Saxena 		if (vdinf->VdState == MPI3_DEVICE0_VD_STATE_OFFLINE)
3363*2d1d418eSSumit Saxena 			tgtdev->is_hidden = 1;
3364*2d1d418eSSumit Saxena 		tgtdev->dev_spec.vol_inf.tg_id = vdinf->IOThrottleGroup;
3365*2d1d418eSSumit Saxena 		tgtdev->dev_spec.vol_inf.tg_high =
3366*2d1d418eSSumit Saxena 			vdinf->IOThrottleGroupHigh * 2048;
3367*2d1d418eSSumit Saxena 		tgtdev->dev_spec.vol_inf.tg_low =
3368*2d1d418eSSumit Saxena 			vdinf->IOThrottleGroupLow * 2048;
3369*2d1d418eSSumit Saxena 		if (vdinf->IOThrottleGroup < sc->num_io_throttle_group) {
3370*2d1d418eSSumit Saxena 			tg = sc->throttle_groups + vdinf->IOThrottleGroup;
3371*2d1d418eSSumit Saxena 			tg->id = vdinf->IOThrottleGroup;
3372*2d1d418eSSumit Saxena 			tg->high = tgtdev->dev_spec.vol_inf.tg_high;
3373*2d1d418eSSumit Saxena 			tg->low = tgtdev->dev_spec.vol_inf.tg_low;
3374*2d1d418eSSumit Saxena 			if (is_added == true)
3375*2d1d418eSSumit Saxena 				tg->fw_qd = tgtdev->q_depth;
3376*2d1d418eSSumit Saxena 			tg->modified_qd = tgtdev->q_depth;
3377*2d1d418eSSumit Saxena 		}
3378*2d1d418eSSumit Saxena 		tgtdev->dev_spec.vol_inf.tg = tg;
3379*2d1d418eSSumit Saxena 		tgtdev->throttle_group = tg;
3380*2d1d418eSSumit Saxena 		break;
3381*2d1d418eSSumit Saxena 	}
3382*2d1d418eSSumit Saxena 	default:
3383*2d1d418eSSumit Saxena 		goto out;
3384*2d1d418eSSumit Saxena 	}
3385*2d1d418eSSumit Saxena 
3386*2d1d418eSSumit Saxena out:
3387*2d1d418eSSumit Saxena 	return;
3388*2d1d418eSSumit Saxena }
3389*2d1d418eSSumit Saxena 
3390*2d1d418eSSumit Saxena int mpi3mr_create_device(struct mpi3mr_softc *sc,
3391*2d1d418eSSumit Saxena     Mpi3DevicePage0_t *dev_pg0)
3392*2d1d418eSSumit Saxena {
3393*2d1d418eSSumit Saxena 	int retval = 0;
3394*2d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
3395*2d1d418eSSumit Saxena 	U16 per_id = 0;
3396*2d1d418eSSumit Saxena 
3397*2d1d418eSSumit Saxena 	per_id = dev_pg0->PersistentID;
3398*2d1d418eSSumit Saxena 
3399*2d1d418eSSumit Saxena 	mtx_lock_spin(&sc->target_lock);
3400*2d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) {
3401*2d1d418eSSumit Saxena 		if (target->per_id == per_id) {
3402*2d1d418eSSumit Saxena 			target->state = MPI3MR_DEV_CREATED;
3403*2d1d418eSSumit Saxena 			break;
3404*2d1d418eSSumit Saxena 		}
3405*2d1d418eSSumit Saxena 	}
3406*2d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->target_lock);
3407*2d1d418eSSumit Saxena 
3408*2d1d418eSSumit Saxena 	if (target) {
3409*2d1d418eSSumit Saxena 			mpi3mr_update_device(sc, target, dev_pg0, true);
3410*2d1d418eSSumit Saxena 	} else {
3411*2d1d418eSSumit Saxena 			target = malloc(sizeof(*target), M_MPI3MR,
3412*2d1d418eSSumit Saxena 				 M_NOWAIT | M_ZERO);
3413*2d1d418eSSumit Saxena 
3414*2d1d418eSSumit Saxena 			if (target == NULL) {
3415*2d1d418eSSumit Saxena 				retval = -1;
3416*2d1d418eSSumit Saxena 				goto out;
3417*2d1d418eSSumit Saxena 			}
3418*2d1d418eSSumit Saxena 
3419*2d1d418eSSumit Saxena 			target->exposed_to_os = 0;
3420*2d1d418eSSumit Saxena 			mpi3mr_update_device(sc, target, dev_pg0, true);
3421*2d1d418eSSumit Saxena 			mtx_lock_spin(&sc->target_lock);
3422*2d1d418eSSumit Saxena 			TAILQ_INSERT_TAIL(&sc->cam_sc->tgt_list, target, tgt_next);
3423*2d1d418eSSumit Saxena 			target->state = MPI3MR_DEV_CREATED;
3424*2d1d418eSSumit Saxena 			mtx_unlock_spin(&sc->target_lock);
3425*2d1d418eSSumit Saxena 	}
3426*2d1d418eSSumit Saxena out:
3427*2d1d418eSSumit Saxena 	return retval;
3428*2d1d418eSSumit Saxena }
3429*2d1d418eSSumit Saxena 
3430*2d1d418eSSumit Saxena /**
3431*2d1d418eSSumit Saxena  * mpi3mr_dev_rmhs_complete_iou - Device removal IOUC completion
3432*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
3433*2d1d418eSSumit Saxena  * @drv_cmd: Internal command tracker
3434*2d1d418eSSumit Saxena  *
3435*2d1d418eSSumit Saxena  * Issues a target reset TM to the firmware from the device
3436*2d1d418eSSumit Saxena  * removal TM pend list or retry the removal handshake sequence
3437*2d1d418eSSumit Saxena  * based on the IOU control request IOC status.
3438*2d1d418eSSumit Saxena  *
3439*2d1d418eSSumit Saxena  * Return: Nothing
3440*2d1d418eSSumit Saxena  */
3441*2d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_softc *sc,
3442*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd)
3443*2d1d418eSSumit Saxena {
3444*2d1d418eSSumit Saxena 	U16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
3445*2d1d418eSSumit Saxena 	struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
3446*2d1d418eSSumit Saxena 
3447*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT,
3448*2d1d418eSSumit Saxena 	    "%s :dev_rmhs_iouctrl_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x)\n",
3449*2d1d418eSSumit Saxena 	    __func__, drv_cmd->dev_handle, drv_cmd->ioc_status,
3450*2d1d418eSSumit Saxena 	    drv_cmd->ioc_loginfo);
3451*2d1d418eSSumit Saxena 	if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) {
3452*2d1d418eSSumit Saxena 		if (drv_cmd->retry_count < MPI3MR_DEVRMHS_RETRYCOUNT) {
3453*2d1d418eSSumit Saxena 			drv_cmd->retry_count++;
3454*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_EVENT,
3455*2d1d418eSSumit Saxena 			    "%s :dev_rmhs_iouctrl_complete: handle(0x%04x)retrying handshake retry=%d\n",
3456*2d1d418eSSumit Saxena 			    __func__, drv_cmd->dev_handle,
3457*2d1d418eSSumit Saxena 			    drv_cmd->retry_count);
3458*2d1d418eSSumit Saxena 			mpi3mr_dev_rmhs_send_tm(sc, drv_cmd->dev_handle,
3459*2d1d418eSSumit Saxena 			    drv_cmd, drv_cmd->iou_rc);
3460*2d1d418eSSumit Saxena 			return;
3461*2d1d418eSSumit Saxena 		}
3462*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
3463*2d1d418eSSumit Saxena 		    "%s :dev removal handshake failed after all retries: handle(0x%04x)\n",
3464*2d1d418eSSumit Saxena 		    __func__, drv_cmd->dev_handle);
3465*2d1d418eSSumit Saxena 	} else {
3466*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
3467*2d1d418eSSumit Saxena 		    "%s :dev removal handshake completed successfully: handle(0x%04x)\n",
3468*2d1d418eSSumit Saxena 		    __func__, drv_cmd->dev_handle);
3469*2d1d418eSSumit Saxena 		mpi3mr_clear_bit(drv_cmd->dev_handle, sc->removepend_bitmap);
3470*2d1d418eSSumit Saxena 	}
3471*2d1d418eSSumit Saxena 
3472*2d1d418eSSumit Saxena 	if (!TAILQ_EMPTY(&sc->delayed_rmhs_list)) {
3473*2d1d418eSSumit Saxena 		delayed_dev_rmhs = TAILQ_FIRST(&sc->delayed_rmhs_list);
3474*2d1d418eSSumit Saxena 		drv_cmd->dev_handle = delayed_dev_rmhs->handle;
3475*2d1d418eSSumit Saxena 		drv_cmd->retry_count = 0;
3476*2d1d418eSSumit Saxena 		drv_cmd->iou_rc = delayed_dev_rmhs->iou_rc;
3477*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT,
3478*2d1d418eSSumit Saxena 		    "%s :dev_rmhs_iouctrl_complete: processing delayed TM: handle(0x%04x)\n",
3479*2d1d418eSSumit Saxena 		    __func__, drv_cmd->dev_handle);
3480*2d1d418eSSumit Saxena 		mpi3mr_dev_rmhs_send_tm(sc, drv_cmd->dev_handle, drv_cmd,
3481*2d1d418eSSumit Saxena 		    drv_cmd->iou_rc);
3482*2d1d418eSSumit Saxena 		TAILQ_REMOVE(&sc->delayed_rmhs_list, delayed_dev_rmhs, list);
3483*2d1d418eSSumit Saxena 		free(delayed_dev_rmhs, M_MPI3MR);
3484*2d1d418eSSumit Saxena 		return;
3485*2d1d418eSSumit Saxena 	}
3486*2d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
3487*2d1d418eSSumit Saxena 	drv_cmd->callback = NULL;
3488*2d1d418eSSumit Saxena 	drv_cmd->retry_count = 0;
3489*2d1d418eSSumit Saxena 	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
3490*2d1d418eSSumit Saxena 	mpi3mr_clear_bit(cmd_idx, sc->devrem_bitmap);
3491*2d1d418eSSumit Saxena }
3492*2d1d418eSSumit Saxena 
3493*2d1d418eSSumit Saxena /**
3494*2d1d418eSSumit Saxena  * mpi3mr_dev_rmhs_complete_tm - Device removal TM completion
3495*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
3496*2d1d418eSSumit Saxena  * @drv_cmd: Internal command tracker
3497*2d1d418eSSumit Saxena  *
3498*2d1d418eSSumit Saxena  * Issues a target reset TM to the firmware from the device
3499*2d1d418eSSumit Saxena  * removal TM pend list or issue IO Unit control request as
3500*2d1d418eSSumit Saxena  * part of device removal or hidden acknowledgment handshake.
3501*2d1d418eSSumit Saxena  *
3502*2d1d418eSSumit Saxena  * Return: Nothing
3503*2d1d418eSSumit Saxena  */
3504*2d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_complete_tm(struct mpi3mr_softc *sc,
3505*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd)
3506*2d1d418eSSumit Saxena {
3507*2d1d418eSSumit Saxena 	Mpi3IoUnitControlRequest_t iou_ctrl;
3508*2d1d418eSSumit Saxena 	U16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
3509*2d1d418eSSumit Saxena 	Mpi3SCSITaskMgmtReply_t *tm_reply = NULL;
3510*2d1d418eSSumit Saxena 	int retval;
3511*2d1d418eSSumit Saxena 
3512*2d1d418eSSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_REPLYVALID)
3513*2d1d418eSSumit Saxena 		tm_reply = (Mpi3SCSITaskMgmtReply_t *)drv_cmd->reply;
3514*2d1d418eSSumit Saxena 
3515*2d1d418eSSumit Saxena 	if (tm_reply)
3516*2d1d418eSSumit Saxena 		printf(IOCNAME
3517*2d1d418eSSumit Saxena 		    "dev_rmhs_tr_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x), term_count(%d)\n",
3518*2d1d418eSSumit Saxena 		    sc->name, drv_cmd->dev_handle, drv_cmd->ioc_status,
3519*2d1d418eSSumit Saxena 		    drv_cmd->ioc_loginfo,
3520*2d1d418eSSumit Saxena 		    le32toh(tm_reply->TerminationCount));
3521*2d1d418eSSumit Saxena 
3522*2d1d418eSSumit Saxena 	printf(IOCNAME "Issuing IOU CTL: handle(0x%04x) dev_rmhs idx(%d)\n",
3523*2d1d418eSSumit Saxena 	    sc->name, drv_cmd->dev_handle, cmd_idx);
3524*2d1d418eSSumit Saxena 
3525*2d1d418eSSumit Saxena 	memset(&iou_ctrl, 0, sizeof(iou_ctrl));
3526*2d1d418eSSumit Saxena 
3527*2d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_PENDING;
3528*2d1d418eSSumit Saxena 	drv_cmd->is_waiting = 0;
3529*2d1d418eSSumit Saxena 	drv_cmd->callback = mpi3mr_dev_rmhs_complete_iou;
3530*2d1d418eSSumit Saxena 	iou_ctrl.Operation = drv_cmd->iou_rc;
3531*2d1d418eSSumit Saxena 	iou_ctrl.Param16[0] = htole16(drv_cmd->dev_handle);
3532*2d1d418eSSumit Saxena 	iou_ctrl.HostTag = htole16(drv_cmd->host_tag);
3533*2d1d418eSSumit Saxena 	iou_ctrl.Function = MPI3_FUNCTION_IO_UNIT_CONTROL;
3534*2d1d418eSSumit Saxena 
3535*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &iou_ctrl, sizeof(iou_ctrl));
3536*2d1d418eSSumit Saxena 	if (retval) {
3537*2d1d418eSSumit Saxena 		printf(IOCNAME "Issue DevRmHsTMIOUCTL: Admin post failed\n",
3538*2d1d418eSSumit Saxena 		    sc->name);
3539*2d1d418eSSumit Saxena 		goto out_failed;
3540*2d1d418eSSumit Saxena 	}
3541*2d1d418eSSumit Saxena 
3542*2d1d418eSSumit Saxena 	return;
3543*2d1d418eSSumit Saxena out_failed:
3544*2d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
3545*2d1d418eSSumit Saxena 	drv_cmd->callback = NULL;
3546*2d1d418eSSumit Saxena 	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
3547*2d1d418eSSumit Saxena 	drv_cmd->retry_count = 0;
3548*2d1d418eSSumit Saxena 	mpi3mr_clear_bit(cmd_idx, sc->devrem_bitmap);
3549*2d1d418eSSumit Saxena }
3550*2d1d418eSSumit Saxena 
3551*2d1d418eSSumit Saxena /**
3552*2d1d418eSSumit Saxena  * mpi3mr_dev_rmhs_send_tm - Issue TM for device removal
3553*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
3554*2d1d418eSSumit Saxena  * @handle: Device handle
3555*2d1d418eSSumit Saxena  * @cmdparam: Internal command tracker
3556*2d1d418eSSumit Saxena  * @iou_rc: IO Unit reason code
3557*2d1d418eSSumit Saxena  *
3558*2d1d418eSSumit Saxena  * Issues a target reset TM to the firmware or add it to a pend
3559*2d1d418eSSumit Saxena  * list as part of device removal or hidden acknowledgment
3560*2d1d418eSSumit Saxena  * handshake.
3561*2d1d418eSSumit Saxena  *
3562*2d1d418eSSumit Saxena  * Return: Nothing
3563*2d1d418eSSumit Saxena  */
3564*2d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_softc *sc, U16 handle,
3565*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdparam, U8 iou_rc)
3566*2d1d418eSSumit Saxena {
3567*2d1d418eSSumit Saxena 	Mpi3SCSITaskMgmtRequest_t tm_req;
3568*2d1d418eSSumit Saxena 	int retval = 0;
3569*2d1d418eSSumit Saxena 	U16 cmd_idx = MPI3MR_NUM_DEVRMCMD;
3570*2d1d418eSSumit Saxena 	U8 retrycount = 5;
3571*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd = cmdparam;
3572*2d1d418eSSumit Saxena 	struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
3573*2d1d418eSSumit Saxena 	struct mpi3mr_target *tgtdev = NULL;
3574*2d1d418eSSumit Saxena 
3575*2d1d418eSSumit Saxena 	mtx_lock_spin(&sc->target_lock);
3576*2d1d418eSSumit Saxena 	TAILQ_FOREACH(tgtdev, &sc->cam_sc->tgt_list, tgt_next) {
3577*2d1d418eSSumit Saxena 		if ((tgtdev->dev_handle == handle) &&
3578*2d1d418eSSumit Saxena 		    (iou_rc == MPI3_CTRL_OP_REMOVE_DEVICE)) {
3579*2d1d418eSSumit Saxena 			tgtdev->state = MPI3MR_DEV_REMOVE_HS_STARTED;
3580*2d1d418eSSumit Saxena 			break;
3581*2d1d418eSSumit Saxena 		}
3582*2d1d418eSSumit Saxena 	}
3583*2d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->target_lock);
3584*2d1d418eSSumit Saxena 
3585*2d1d418eSSumit Saxena 	if (drv_cmd)
3586*2d1d418eSSumit Saxena 		goto issue_cmd;
3587*2d1d418eSSumit Saxena 	do {
3588*2d1d418eSSumit Saxena 		cmd_idx = mpi3mr_find_first_zero_bit(sc->devrem_bitmap,
3589*2d1d418eSSumit Saxena 		    MPI3MR_NUM_DEVRMCMD);
3590*2d1d418eSSumit Saxena 		if (cmd_idx < MPI3MR_NUM_DEVRMCMD) {
3591*2d1d418eSSumit Saxena 			if (!mpi3mr_test_and_set_bit(cmd_idx, sc->devrem_bitmap))
3592*2d1d418eSSumit Saxena 				break;
3593*2d1d418eSSumit Saxena 			cmd_idx = MPI3MR_NUM_DEVRMCMD;
3594*2d1d418eSSumit Saxena 		}
3595*2d1d418eSSumit Saxena 	} while (retrycount--);
3596*2d1d418eSSumit Saxena 
3597*2d1d418eSSumit Saxena 	if (cmd_idx >= MPI3MR_NUM_DEVRMCMD) {
3598*2d1d418eSSumit Saxena 		delayed_dev_rmhs = malloc(sizeof(*delayed_dev_rmhs),M_MPI3MR,
3599*2d1d418eSSumit Saxena 		     M_ZERO|M_NOWAIT);
3600*2d1d418eSSumit Saxena 
3601*2d1d418eSSumit Saxena 		if (!delayed_dev_rmhs)
3602*2d1d418eSSumit Saxena 			return;
3603*2d1d418eSSumit Saxena 		delayed_dev_rmhs->handle = handle;
3604*2d1d418eSSumit Saxena 		delayed_dev_rmhs->iou_rc = iou_rc;
3605*2d1d418eSSumit Saxena 		TAILQ_INSERT_TAIL(&(sc->delayed_rmhs_list), delayed_dev_rmhs, list);
3606*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :DevRmHs: tr:handle(0x%04x) is postponed\n",
3607*2d1d418eSSumit Saxena 		    __func__, handle);
3608*2d1d418eSSumit Saxena 
3609*2d1d418eSSumit Saxena 
3610*2d1d418eSSumit Saxena 		return;
3611*2d1d418eSSumit Saxena 	}
3612*2d1d418eSSumit Saxena 	drv_cmd = &sc->dev_rmhs_cmds[cmd_idx];
3613*2d1d418eSSumit Saxena 
3614*2d1d418eSSumit Saxena issue_cmd:
3615*2d1d418eSSumit Saxena 	cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
3616*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT,
3617*2d1d418eSSumit Saxena 	    "%s :Issuing TR TM: for devhandle 0x%04x with dev_rmhs %d\n",
3618*2d1d418eSSumit Saxena 	    __func__, handle, cmd_idx);
3619*2d1d418eSSumit Saxena 
3620*2d1d418eSSumit Saxena 	memset(&tm_req, 0, sizeof(tm_req));
3621*2d1d418eSSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_PENDING) {
3622*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :Issue TM: Command is in use\n", __func__);
3623*2d1d418eSSumit Saxena 		goto out;
3624*2d1d418eSSumit Saxena 	}
3625*2d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_PENDING;
3626*2d1d418eSSumit Saxena 	drv_cmd->is_waiting = 0;
3627*2d1d418eSSumit Saxena 	drv_cmd->callback = mpi3mr_dev_rmhs_complete_tm;
3628*2d1d418eSSumit Saxena 	drv_cmd->dev_handle = handle;
3629*2d1d418eSSumit Saxena 	drv_cmd->iou_rc = iou_rc;
3630*2d1d418eSSumit Saxena 	tm_req.DevHandle = htole16(handle);
3631*2d1d418eSSumit Saxena 	tm_req.TaskType = MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
3632*2d1d418eSSumit Saxena 	tm_req.HostTag = htole16(drv_cmd->host_tag);
3633*2d1d418eSSumit Saxena 	tm_req.TaskHostTag = htole16(MPI3MR_HOSTTAG_INVALID);
3634*2d1d418eSSumit Saxena 	tm_req.Function = MPI3_FUNCTION_SCSI_TASK_MGMT;
3635*2d1d418eSSumit Saxena 
3636*2d1d418eSSumit Saxena 	mpi3mr_set_bit(handle, sc->removepend_bitmap);
3637*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &tm_req, sizeof(tm_req));
3638*2d1d418eSSumit Saxena 	if (retval) {
3639*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "%s :Issue DevRmHsTM: Admin Post failed\n",
3640*2d1d418eSSumit Saxena 		    __func__);
3641*2d1d418eSSumit Saxena 		goto out_failed;
3642*2d1d418eSSumit Saxena 	}
3643*2d1d418eSSumit Saxena out:
3644*2d1d418eSSumit Saxena 	return;
3645*2d1d418eSSumit Saxena out_failed:
3646*2d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
3647*2d1d418eSSumit Saxena 	drv_cmd->callback = NULL;
3648*2d1d418eSSumit Saxena 	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
3649*2d1d418eSSumit Saxena 	drv_cmd->retry_count = 0;
3650*2d1d418eSSumit Saxena 	mpi3mr_clear_bit(cmd_idx, sc->devrem_bitmap);
3651*2d1d418eSSumit Saxena }
3652*2d1d418eSSumit Saxena 
3653*2d1d418eSSumit Saxena /**
3654*2d1d418eSSumit Saxena  * mpi3mr_complete_evt_ack - Event ack request completion
3655*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
3656*2d1d418eSSumit Saxena  * @drv_cmd: Internal command tracker
3657*2d1d418eSSumit Saxena  *
3658*2d1d418eSSumit Saxena  * This is the completion handler for non blocking event
3659*2d1d418eSSumit Saxena  * acknowledgment sent to the firmware and this will issue any
3660*2d1d418eSSumit Saxena  * pending event acknowledgment request.
3661*2d1d418eSSumit Saxena  *
3662*2d1d418eSSumit Saxena  * Return: Nothing
3663*2d1d418eSSumit Saxena  */
3664*2d1d418eSSumit Saxena static void mpi3mr_complete_evt_ack(struct mpi3mr_softc *sc,
3665*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd)
3666*2d1d418eSSumit Saxena {
3667*2d1d418eSSumit Saxena 	U16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
3668*2d1d418eSSumit Saxena 	struct delayed_evtack_node *delayed_evtack = NULL;
3669*2d1d418eSSumit Saxena 
3670*2d1d418eSSumit Saxena 	if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) {
3671*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT,
3672*2d1d418eSSumit Saxena 		    "%s: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n", __func__,
3673*2d1d418eSSumit Saxena 		    (drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
3674*2d1d418eSSumit Saxena 		    drv_cmd->ioc_loginfo);
3675*2d1d418eSSumit Saxena 	}
3676*2d1d418eSSumit Saxena 
3677*2d1d418eSSumit Saxena 	if (!TAILQ_EMPTY(&sc->delayed_evtack_cmds_list)) {
3678*2d1d418eSSumit Saxena 		delayed_evtack = TAILQ_FIRST(&sc->delayed_evtack_cmds_list);
3679*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT,
3680*2d1d418eSSumit Saxena 		    "%s: processing delayed event ack for event %d\n",
3681*2d1d418eSSumit Saxena 		    __func__, delayed_evtack->event);
3682*2d1d418eSSumit Saxena 		mpi3mr_send_evt_ack(sc, delayed_evtack->event, drv_cmd,
3683*2d1d418eSSumit Saxena 		    delayed_evtack->event_ctx);
3684*2d1d418eSSumit Saxena 		TAILQ_REMOVE(&sc->delayed_evtack_cmds_list, delayed_evtack, list);
3685*2d1d418eSSumit Saxena 		free(delayed_evtack, M_MPI3MR);
3686*2d1d418eSSumit Saxena 		return;
3687*2d1d418eSSumit Saxena 	}
3688*2d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
3689*2d1d418eSSumit Saxena 	drv_cmd->callback = NULL;
3690*2d1d418eSSumit Saxena 	mpi3mr_clear_bit(cmd_idx, sc->evtack_cmds_bitmap);
3691*2d1d418eSSumit Saxena }
3692*2d1d418eSSumit Saxena 
3693*2d1d418eSSumit Saxena /**
3694*2d1d418eSSumit Saxena  * mpi3mr_send_evt_ack - Issue event acknwoledgment request
3695*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
3696*2d1d418eSSumit Saxena  * @event: MPI3 event id
3697*2d1d418eSSumit Saxena  * @cmdparam: Internal command tracker
3698*2d1d418eSSumit Saxena  * @event_ctx: Event context
3699*2d1d418eSSumit Saxena  *
3700*2d1d418eSSumit Saxena  * Issues event acknowledgment request to the firmware if there
3701*2d1d418eSSumit Saxena  * is a free command to send the event ack else it to a pend
3702*2d1d418eSSumit Saxena  * list so that it will be processed on a completion of a prior
3703*2d1d418eSSumit Saxena  * event acknowledgment .
3704*2d1d418eSSumit Saxena  *
3705*2d1d418eSSumit Saxena  * Return: Nothing
3706*2d1d418eSSumit Saxena  */
3707*2d1d418eSSumit Saxena static void mpi3mr_send_evt_ack(struct mpi3mr_softc *sc, U8 event,
3708*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdparam, U32 event_ctx)
3709*2d1d418eSSumit Saxena {
3710*2d1d418eSSumit Saxena 	Mpi3EventAckRequest_t evtack_req;
3711*2d1d418eSSumit Saxena 	int retval = 0;
3712*2d1d418eSSumit Saxena 	U8 retrycount = 5;
3713*2d1d418eSSumit Saxena 	U16 cmd_idx = MPI3MR_NUM_EVTACKCMD;
3714*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd = cmdparam;
3715*2d1d418eSSumit Saxena 	struct delayed_evtack_node *delayed_evtack = NULL;
3716*2d1d418eSSumit Saxena 
3717*2d1d418eSSumit Saxena 	if (drv_cmd)
3718*2d1d418eSSumit Saxena 		goto issue_cmd;
3719*2d1d418eSSumit Saxena 	do {
3720*2d1d418eSSumit Saxena 		cmd_idx = mpi3mr_find_first_zero_bit(sc->evtack_cmds_bitmap,
3721*2d1d418eSSumit Saxena 		    MPI3MR_NUM_EVTACKCMD);
3722*2d1d418eSSumit Saxena 		if (cmd_idx < MPI3MR_NUM_EVTACKCMD) {
3723*2d1d418eSSumit Saxena 			if (!mpi3mr_test_and_set_bit(cmd_idx,
3724*2d1d418eSSumit Saxena 			    sc->evtack_cmds_bitmap))
3725*2d1d418eSSumit Saxena 				break;
3726*2d1d418eSSumit Saxena 			cmd_idx = MPI3MR_NUM_EVTACKCMD;
3727*2d1d418eSSumit Saxena 		}
3728*2d1d418eSSumit Saxena 	} while (retrycount--);
3729*2d1d418eSSumit Saxena 
3730*2d1d418eSSumit Saxena 	if (cmd_idx >= MPI3MR_NUM_EVTACKCMD) {
3731*2d1d418eSSumit Saxena 		delayed_evtack = malloc(sizeof(*delayed_evtack),M_MPI3MR,
3732*2d1d418eSSumit Saxena 		     M_ZERO | M_NOWAIT);
3733*2d1d418eSSumit Saxena 		if (!delayed_evtack)
3734*2d1d418eSSumit Saxena 			return;
3735*2d1d418eSSumit Saxena 		delayed_evtack->event = event;
3736*2d1d418eSSumit Saxena 		delayed_evtack->event_ctx = event_ctx;
3737*2d1d418eSSumit Saxena 		TAILQ_INSERT_TAIL(&(sc->delayed_evtack_cmds_list), delayed_evtack, list);
3738*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s : Event ack for event:%d is postponed\n",
3739*2d1d418eSSumit Saxena 		    __func__, event);
3740*2d1d418eSSumit Saxena 		return;
3741*2d1d418eSSumit Saxena 	}
3742*2d1d418eSSumit Saxena 	drv_cmd = &sc->evtack_cmds[cmd_idx];
3743*2d1d418eSSumit Saxena 
3744*2d1d418eSSumit Saxena issue_cmd:
3745*2d1d418eSSumit Saxena 	cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
3746*2d1d418eSSumit Saxena 
3747*2d1d418eSSumit Saxena 	memset(&evtack_req, 0, sizeof(evtack_req));
3748*2d1d418eSSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_PENDING) {
3749*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s: Command is in use\n", __func__);
3750*2d1d418eSSumit Saxena 		goto out;
3751*2d1d418eSSumit Saxena 	}
3752*2d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_PENDING;
3753*2d1d418eSSumit Saxena 	drv_cmd->is_waiting = 0;
3754*2d1d418eSSumit Saxena 	drv_cmd->callback = mpi3mr_complete_evt_ack;
3755*2d1d418eSSumit Saxena 	evtack_req.HostTag = htole16(drv_cmd->host_tag);
3756*2d1d418eSSumit Saxena 	evtack_req.Function = MPI3_FUNCTION_EVENT_ACK;
3757*2d1d418eSSumit Saxena 	evtack_req.Event = event;
3758*2d1d418eSSumit Saxena 	evtack_req.EventContext = htole32(event_ctx);
3759*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &evtack_req,
3760*2d1d418eSSumit Saxena 	    sizeof(evtack_req));
3761*2d1d418eSSumit Saxena 
3762*2d1d418eSSumit Saxena 	if (retval) {
3763*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "%s: Admin Post failed\n", __func__);
3764*2d1d418eSSumit Saxena 		goto out_failed;
3765*2d1d418eSSumit Saxena 	}
3766*2d1d418eSSumit Saxena out:
3767*2d1d418eSSumit Saxena 	return;
3768*2d1d418eSSumit Saxena out_failed:
3769*2d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
3770*2d1d418eSSumit Saxena 	drv_cmd->callback = NULL;
3771*2d1d418eSSumit Saxena 	mpi3mr_clear_bit(cmd_idx, sc->evtack_cmds_bitmap);
3772*2d1d418eSSumit Saxena }
3773*2d1d418eSSumit Saxena 
3774*2d1d418eSSumit Saxena /*
3775*2d1d418eSSumit Saxena  * mpi3mr_pcietopochg_evt_th - PCIETopologyChange evt tophalf
3776*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
3777*2d1d418eSSumit Saxena  * @event_reply: Event data
3778*2d1d418eSSumit Saxena  *
3779*2d1d418eSSumit Saxena  * Checks for the reason code and based on that either block I/O
3780*2d1d418eSSumit Saxena  * to device, or unblock I/O to the device, or start the device
3781*2d1d418eSSumit Saxena  * removal handshake with reason as remove with the firmware for
3782*2d1d418eSSumit Saxena  * PCIe devices.
3783*2d1d418eSSumit Saxena  *
3784*2d1d418eSSumit Saxena  * Return: Nothing
3785*2d1d418eSSumit Saxena  */
3786*2d1d418eSSumit Saxena static void mpi3mr_pcietopochg_evt_th(struct mpi3mr_softc *sc,
3787*2d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
3788*2d1d418eSSumit Saxena {
3789*2d1d418eSSumit Saxena 	Mpi3EventDataPcieTopologyChangeList_t *topo_evt =
3790*2d1d418eSSumit Saxena 	    (Mpi3EventDataPcieTopologyChangeList_t *) event_reply->EventData;
3791*2d1d418eSSumit Saxena 	int i;
3792*2d1d418eSSumit Saxena 	U16 handle;
3793*2d1d418eSSumit Saxena 	U8 reason_code;
3794*2d1d418eSSumit Saxena 	struct mpi3mr_target *tgtdev = NULL;
3795*2d1d418eSSumit Saxena 
3796*2d1d418eSSumit Saxena 	for (i = 0; i < topo_evt->NumEntries; i++) {
3797*2d1d418eSSumit Saxena 		handle = le16toh(topo_evt->PortEntry[i].AttachedDevHandle);
3798*2d1d418eSSumit Saxena 		if (!handle)
3799*2d1d418eSSumit Saxena 			continue;
3800*2d1d418eSSumit Saxena 		reason_code = topo_evt->PortEntry[i].PortStatus;
3801*2d1d418eSSumit Saxena 		tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle);
3802*2d1d418eSSumit Saxena 		switch (reason_code) {
3803*2d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
3804*2d1d418eSSumit Saxena 			if (tgtdev) {
3805*2d1d418eSSumit Saxena 				tgtdev->dev_removed = 1;
3806*2d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 0;
3807*2d1d418eSSumit Saxena 				mpi3mr_atomic_set(&tgtdev->block_io, 0);
3808*2d1d418eSSumit Saxena 			}
3809*2d1d418eSSumit Saxena 			mpi3mr_dev_rmhs_send_tm(sc, handle, NULL,
3810*2d1d418eSSumit Saxena 			    MPI3_CTRL_OP_REMOVE_DEVICE);
3811*2d1d418eSSumit Saxena 			break;
3812*2d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
3813*2d1d418eSSumit Saxena 			if (tgtdev) {
3814*2d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 1;
3815*2d1d418eSSumit Saxena 				mpi3mr_atomic_inc(&tgtdev->block_io);
3816*2d1d418eSSumit Saxena 			}
3817*2d1d418eSSumit Saxena 			break;
3818*2d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_RESPONDING:
3819*2d1d418eSSumit Saxena 			if (tgtdev &&
3820*2d1d418eSSumit Saxena 			    tgtdev->dev_removedelay) {
3821*2d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 0;
3822*2d1d418eSSumit Saxena 				if (mpi3mr_atomic_read(&tgtdev->block_io) > 0)
3823*2d1d418eSSumit Saxena 					mpi3mr_atomic_dec(&tgtdev->block_io);
3824*2d1d418eSSumit Saxena 			}
3825*2d1d418eSSumit Saxena 			break;
3826*2d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
3827*2d1d418eSSumit Saxena 		default:
3828*2d1d418eSSumit Saxena 			break;
3829*2d1d418eSSumit Saxena 		}
3830*2d1d418eSSumit Saxena 	}
3831*2d1d418eSSumit Saxena }
3832*2d1d418eSSumit Saxena 
3833*2d1d418eSSumit Saxena /**
3834*2d1d418eSSumit Saxena  * mpi3mr_sastopochg_evt_th - SASTopologyChange evt tophalf
3835*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
3836*2d1d418eSSumit Saxena  * @event_reply: Event data
3837*2d1d418eSSumit Saxena  *
3838*2d1d418eSSumit Saxena  * Checks for the reason code and based on that either block I/O
3839*2d1d418eSSumit Saxena  * to device, or unblock I/O to the device, or start the device
3840*2d1d418eSSumit Saxena  * removal handshake with reason as remove with the firmware for
3841*2d1d418eSSumit Saxena  * SAS/SATA devices.
3842*2d1d418eSSumit Saxena  *
3843*2d1d418eSSumit Saxena  * Return: Nothing
3844*2d1d418eSSumit Saxena  */
3845*2d1d418eSSumit Saxena static void mpi3mr_sastopochg_evt_th(struct mpi3mr_softc *sc,
3846*2d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
3847*2d1d418eSSumit Saxena {
3848*2d1d418eSSumit Saxena 	Mpi3EventDataSasTopologyChangeList_t *topo_evt =
3849*2d1d418eSSumit Saxena 	    (Mpi3EventDataSasTopologyChangeList_t *)event_reply->EventData;
3850*2d1d418eSSumit Saxena 	int i;
3851*2d1d418eSSumit Saxena 	U16 handle;
3852*2d1d418eSSumit Saxena 	U8 reason_code;
3853*2d1d418eSSumit Saxena 	struct mpi3mr_target *tgtdev = NULL;
3854*2d1d418eSSumit Saxena 
3855*2d1d418eSSumit Saxena 	for (i = 0; i < topo_evt->NumEntries; i++) {
3856*2d1d418eSSumit Saxena 		handle = le16toh(topo_evt->PhyEntry[i].AttachedDevHandle);
3857*2d1d418eSSumit Saxena 		if (!handle)
3858*2d1d418eSSumit Saxena 			continue;
3859*2d1d418eSSumit Saxena 		reason_code = topo_evt->PhyEntry[i].Status &
3860*2d1d418eSSumit Saxena 		    MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
3861*2d1d418eSSumit Saxena 		tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle);
3862*2d1d418eSSumit Saxena 		switch (reason_code) {
3863*2d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
3864*2d1d418eSSumit Saxena 			if (tgtdev) {
3865*2d1d418eSSumit Saxena 				tgtdev->dev_removed = 1;
3866*2d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 0;
3867*2d1d418eSSumit Saxena 				mpi3mr_atomic_set(&tgtdev->block_io, 0);
3868*2d1d418eSSumit Saxena 			}
3869*2d1d418eSSumit Saxena 			mpi3mr_dev_rmhs_send_tm(sc, handle, NULL,
3870*2d1d418eSSumit Saxena 			    MPI3_CTRL_OP_REMOVE_DEVICE);
3871*2d1d418eSSumit Saxena 			break;
3872*2d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING:
3873*2d1d418eSSumit Saxena 			if (tgtdev) {
3874*2d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 1;
3875*2d1d418eSSumit Saxena 				mpi3mr_atomic_inc(&tgtdev->block_io);
3876*2d1d418eSSumit Saxena 			}
3877*2d1d418eSSumit Saxena 			break;
3878*2d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
3879*2d1d418eSSumit Saxena 			if (tgtdev &&
3880*2d1d418eSSumit Saxena 			    tgtdev->dev_removedelay) {
3881*2d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 0;
3882*2d1d418eSSumit Saxena 				if (mpi3mr_atomic_read(&tgtdev->block_io) > 0)
3883*2d1d418eSSumit Saxena 					mpi3mr_atomic_dec(&tgtdev->block_io);
3884*2d1d418eSSumit Saxena 			}
3885*2d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
3886*2d1d418eSSumit Saxena 		default:
3887*2d1d418eSSumit Saxena 			break;
3888*2d1d418eSSumit Saxena 		}
3889*2d1d418eSSumit Saxena 	}
3890*2d1d418eSSumit Saxena 
3891*2d1d418eSSumit Saxena }
3892*2d1d418eSSumit Saxena /**
3893*2d1d418eSSumit Saxena  * mpi3mr_devstatuschg_evt_th - DeviceStatusChange evt tophalf
3894*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
3895*2d1d418eSSumit Saxena  * @event_reply: Event data
3896*2d1d418eSSumit Saxena  *
3897*2d1d418eSSumit Saxena  * Checks for the reason code and based on that either block I/O
3898*2d1d418eSSumit Saxena  * to device, or unblock I/O to the device, or start the device
3899*2d1d418eSSumit Saxena  * removal handshake with reason as remove/hide acknowledgment
3900*2d1d418eSSumit Saxena  * with the firmware.
3901*2d1d418eSSumit Saxena  *
3902*2d1d418eSSumit Saxena  * Return: Nothing
3903*2d1d418eSSumit Saxena  */
3904*2d1d418eSSumit Saxena static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_softc *sc,
3905*2d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
3906*2d1d418eSSumit Saxena {
3907*2d1d418eSSumit Saxena 	U16 dev_handle = 0;
3908*2d1d418eSSumit Saxena 	U8 ublock = 0, block = 0, hide = 0, uhide = 0, delete = 0, remove = 0;
3909*2d1d418eSSumit Saxena 	struct mpi3mr_target *tgtdev = NULL;
3910*2d1d418eSSumit Saxena 	Mpi3EventDataDeviceStatusChange_t *evtdata =
3911*2d1d418eSSumit Saxena 	    (Mpi3EventDataDeviceStatusChange_t *) event_reply->EventData;
3912*2d1d418eSSumit Saxena 
3913*2d1d418eSSumit Saxena 	dev_handle = le16toh(evtdata->DevHandle);
3914*2d1d418eSSumit Saxena 
3915*2d1d418eSSumit Saxena 	switch (evtdata->ReasonCode) {
3916*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT:
3917*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_STRT:
3918*2d1d418eSSumit Saxena 		block = 1;
3919*2d1d418eSSumit Saxena 		break;
3920*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_HIDDEN:
3921*2d1d418eSSumit Saxena 		delete = 1;
3922*2d1d418eSSumit Saxena 		hide = 1;
3923*2d1d418eSSumit Saxena 		break;
3924*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN:
3925*2d1d418eSSumit Saxena 		uhide = 1;
3926*2d1d418eSSumit Saxena 		break;
3927*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING:
3928*2d1d418eSSumit Saxena 		delete = 1;
3929*2d1d418eSSumit Saxena 		remove = 1;
3930*2d1d418eSSumit Saxena 		break;
3931*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_CMP:
3932*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_CMP:
3933*2d1d418eSSumit Saxena 		ublock = 1;
3934*2d1d418eSSumit Saxena 		break;
3935*2d1d418eSSumit Saxena 	default:
3936*2d1d418eSSumit Saxena 		break;
3937*2d1d418eSSumit Saxena 	}
3938*2d1d418eSSumit Saxena 
3939*2d1d418eSSumit Saxena 	tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle);
3940*2d1d418eSSumit Saxena 
3941*2d1d418eSSumit Saxena 	if (!tgtdev) {
3942*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "%s :target with dev_handle:0x%x not found\n",
3943*2d1d418eSSumit Saxena 		    __func__, dev_handle);
3944*2d1d418eSSumit Saxena 		return;
3945*2d1d418eSSumit Saxena 	}
3946*2d1d418eSSumit Saxena 
3947*2d1d418eSSumit Saxena 	if (block)
3948*2d1d418eSSumit Saxena 		mpi3mr_atomic_inc(&tgtdev->block_io);
3949*2d1d418eSSumit Saxena 
3950*2d1d418eSSumit Saxena 	if (hide)
3951*2d1d418eSSumit Saxena 		tgtdev->is_hidden = hide;
3952*2d1d418eSSumit Saxena 
3953*2d1d418eSSumit Saxena 	if (uhide) {
3954*2d1d418eSSumit Saxena 		tgtdev->is_hidden = 0;
3955*2d1d418eSSumit Saxena 		tgtdev->dev_removed = 0;
3956*2d1d418eSSumit Saxena 	}
3957*2d1d418eSSumit Saxena 
3958*2d1d418eSSumit Saxena 	if (delete)
3959*2d1d418eSSumit Saxena 		tgtdev->dev_removed = 1;
3960*2d1d418eSSumit Saxena 
3961*2d1d418eSSumit Saxena 	if (ublock) {
3962*2d1d418eSSumit Saxena 		if (mpi3mr_atomic_read(&tgtdev->block_io) > 0)
3963*2d1d418eSSumit Saxena 			mpi3mr_atomic_dec(&tgtdev->block_io);
3964*2d1d418eSSumit Saxena 	}
3965*2d1d418eSSumit Saxena 
3966*2d1d418eSSumit Saxena 	if (remove) {
3967*2d1d418eSSumit Saxena 		mpi3mr_dev_rmhs_send_tm(sc, dev_handle, NULL,
3968*2d1d418eSSumit Saxena 					MPI3_CTRL_OP_REMOVE_DEVICE);
3969*2d1d418eSSumit Saxena 	}
3970*2d1d418eSSumit Saxena 	if (hide)
3971*2d1d418eSSumit Saxena 		mpi3mr_dev_rmhs_send_tm(sc, dev_handle, NULL,
3972*2d1d418eSSumit Saxena 					MPI3_CTRL_OP_HIDDEN_ACK);
3973*2d1d418eSSumit Saxena }
3974*2d1d418eSSumit Saxena 
3975*2d1d418eSSumit Saxena /**
3976*2d1d418eSSumit Saxena  * mpi3mr_preparereset_evt_th - Prepareforreset evt tophalf
3977*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
3978*2d1d418eSSumit Saxena  * @event_reply: Event data
3979*2d1d418eSSumit Saxena  *
3980*2d1d418eSSumit Saxena  * Blocks and unblocks host level I/O based on the reason code
3981*2d1d418eSSumit Saxena  *
3982*2d1d418eSSumit Saxena  * Return: Nothing
3983*2d1d418eSSumit Saxena  */
3984*2d1d418eSSumit Saxena static void mpi3mr_preparereset_evt_th(struct mpi3mr_softc *sc,
3985*2d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
3986*2d1d418eSSumit Saxena {
3987*2d1d418eSSumit Saxena 	Mpi3EventDataPrepareForReset_t *evtdata =
3988*2d1d418eSSumit Saxena 	    (Mpi3EventDataPrepareForReset_t *)event_reply->EventData;
3989*2d1d418eSSumit Saxena 
3990*2d1d418eSSumit Saxena 	if (evtdata->ReasonCode == MPI3_EVENT_PREPARE_RESET_RC_START) {
3991*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :Recieved PrepForReset Event with RC=START\n",
3992*2d1d418eSSumit Saxena 		    __func__);
3993*2d1d418eSSumit Saxena 		if (sc->prepare_for_reset)
3994*2d1d418eSSumit Saxena 			return;
3995*2d1d418eSSumit Saxena 		sc->prepare_for_reset = 1;
3996*2d1d418eSSumit Saxena 		sc->prepare_for_reset_timeout_counter = 0;
3997*2d1d418eSSumit Saxena 	} else if (evtdata->ReasonCode == MPI3_EVENT_PREPARE_RESET_RC_ABORT) {
3998*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :Recieved PrepForReset Event with RC=ABORT\n",
3999*2d1d418eSSumit Saxena 		    __func__);
4000*2d1d418eSSumit Saxena 		sc->prepare_for_reset = 0;
4001*2d1d418eSSumit Saxena 		sc->prepare_for_reset_timeout_counter = 0;
4002*2d1d418eSSumit Saxena 	}
4003*2d1d418eSSumit Saxena 	if ((event_reply->MsgFlags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK)
4004*2d1d418eSSumit Saxena 	    == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED)
4005*2d1d418eSSumit Saxena 		mpi3mr_send_evt_ack(sc, event_reply->Event, NULL,
4006*2d1d418eSSumit Saxena 		    le32toh(event_reply->EventContext));
4007*2d1d418eSSumit Saxena }
4008*2d1d418eSSumit Saxena 
4009*2d1d418eSSumit Saxena /**
4010*2d1d418eSSumit Saxena  * mpi3mr_energypackchg_evt_th - Energypackchange evt tophalf
4011*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
4012*2d1d418eSSumit Saxena  * @event_reply: Event data
4013*2d1d418eSSumit Saxena  *
4014*2d1d418eSSumit Saxena  * Identifies the new shutdown timeout value and update.
4015*2d1d418eSSumit Saxena  *
4016*2d1d418eSSumit Saxena  * Return: Nothing
4017*2d1d418eSSumit Saxena  */
4018*2d1d418eSSumit Saxena static void mpi3mr_energypackchg_evt_th(struct mpi3mr_softc *sc,
4019*2d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
4020*2d1d418eSSumit Saxena {
4021*2d1d418eSSumit Saxena 	Mpi3EventDataEnergyPackChange_t *evtdata =
4022*2d1d418eSSumit Saxena 	    (Mpi3EventDataEnergyPackChange_t *)event_reply->EventData;
4023*2d1d418eSSumit Saxena 	U16 shutdown_timeout = le16toh(evtdata->ShutdownTimeout);
4024*2d1d418eSSumit Saxena 
4025*2d1d418eSSumit Saxena 	if (shutdown_timeout <= 0) {
4026*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
4027*2d1d418eSSumit Saxena 		    "%s :Invalid Shutdown Timeout received = %d\n",
4028*2d1d418eSSumit Saxena 		    __func__, shutdown_timeout);
4029*2d1d418eSSumit Saxena 		return;
4030*2d1d418eSSumit Saxena 	}
4031*2d1d418eSSumit Saxena 
4032*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT,
4033*2d1d418eSSumit Saxena 	    "%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n",
4034*2d1d418eSSumit Saxena 	    __func__, sc->facts.shutdown_timeout, shutdown_timeout);
4035*2d1d418eSSumit Saxena 	sc->facts.shutdown_timeout = shutdown_timeout;
4036*2d1d418eSSumit Saxena }
4037*2d1d418eSSumit Saxena 
4038*2d1d418eSSumit Saxena /**
4039*2d1d418eSSumit Saxena  * mpi3mr_cablemgmt_evt_th - Cable mgmt evt tophalf
4040*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
4041*2d1d418eSSumit Saxena  * @event_reply: Event data
4042*2d1d418eSSumit Saxena  *
4043*2d1d418eSSumit Saxena  * Displays Cable manegemt event details.
4044*2d1d418eSSumit Saxena  *
4045*2d1d418eSSumit Saxena  * Return: Nothing
4046*2d1d418eSSumit Saxena  */
4047*2d1d418eSSumit Saxena static void mpi3mr_cablemgmt_evt_th(struct mpi3mr_softc *sc,
4048*2d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
4049*2d1d418eSSumit Saxena {
4050*2d1d418eSSumit Saxena 	Mpi3EventDataCableManagement_t *evtdata =
4051*2d1d418eSSumit Saxena 	    (Mpi3EventDataCableManagement_t *)event_reply->EventData;
4052*2d1d418eSSumit Saxena 
4053*2d1d418eSSumit Saxena 	switch (evtdata->Status) {
4054*2d1d418eSSumit Saxena 	case MPI3_EVENT_CABLE_MGMT_STATUS_INSUFFICIENT_POWER:
4055*2d1d418eSSumit Saxena 	{
4056*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "An active cable with ReceptacleID %d cannot be powered.\n"
4057*2d1d418eSSumit Saxena 		    "Devices connected to this cable are not detected.\n"
4058*2d1d418eSSumit Saxena 		    "This cable requires %d mW of power.\n",
4059*2d1d418eSSumit Saxena 		    evtdata->ReceptacleID,
4060*2d1d418eSSumit Saxena 		    le32toh(evtdata->ActiveCablePowerRequirement));
4061*2d1d418eSSumit Saxena 		break;
4062*2d1d418eSSumit Saxena 	}
4063*2d1d418eSSumit Saxena 	case MPI3_EVENT_CABLE_MGMT_STATUS_DEGRADED:
4064*2d1d418eSSumit Saxena 	{
4065*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "A cable with ReceptacleID %d is not running at optimal speed\n",
4066*2d1d418eSSumit Saxena 		    evtdata->ReceptacleID);
4067*2d1d418eSSumit Saxena 		break;
4068*2d1d418eSSumit Saxena 	}
4069*2d1d418eSSumit Saxena 	default:
4070*2d1d418eSSumit Saxena 		break;
4071*2d1d418eSSumit Saxena 	}
4072*2d1d418eSSumit Saxena }
4073*2d1d418eSSumit Saxena 
4074*2d1d418eSSumit Saxena /**
4075*2d1d418eSSumit Saxena  * mpi3mr_process_events - Event's toph-half handler
4076*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
4077*2d1d418eSSumit Saxena  * @event_reply: Event data
4078*2d1d418eSSumit Saxena  *
4079*2d1d418eSSumit Saxena  * Top half of event processing.
4080*2d1d418eSSumit Saxena  *
4081*2d1d418eSSumit Saxena  * Return: Nothing
4082*2d1d418eSSumit Saxena  */
4083*2d1d418eSSumit Saxena static void mpi3mr_process_events(struct mpi3mr_softc *sc,
4084*2d1d418eSSumit Saxena     uintptr_t data, Mpi3EventNotificationReply_t *event_reply)
4085*2d1d418eSSumit Saxena {
4086*2d1d418eSSumit Saxena 	U16 evt_type;
4087*2d1d418eSSumit Saxena 	bool ack_req = 0, process_evt_bh = 0;
4088*2d1d418eSSumit Saxena 	struct mpi3mr_fw_event_work *fw_event;
4089*2d1d418eSSumit Saxena 	U16 sz;
4090*2d1d418eSSumit Saxena 
4091*2d1d418eSSumit Saxena 	if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN)
4092*2d1d418eSSumit Saxena 		goto out;
4093*2d1d418eSSumit Saxena 
4094*2d1d418eSSumit Saxena 	if ((event_reply->MsgFlags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK)
4095*2d1d418eSSumit Saxena 	    == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED)
4096*2d1d418eSSumit Saxena 		ack_req = 1;
4097*2d1d418eSSumit Saxena 
4098*2d1d418eSSumit Saxena 	evt_type = event_reply->Event;
4099*2d1d418eSSumit Saxena 
4100*2d1d418eSSumit Saxena 	switch (evt_type) {
4101*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_ADDED:
4102*2d1d418eSSumit Saxena 	{
4103*2d1d418eSSumit Saxena 		Mpi3DevicePage0_t *dev_pg0 =
4104*2d1d418eSSumit Saxena 			(Mpi3DevicePage0_t *) event_reply->EventData;
4105*2d1d418eSSumit Saxena 		if (mpi3mr_create_device(sc, dev_pg0))
4106*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
4107*2d1d418eSSumit Saxena 			"%s :Failed to add device in the device add event\n",
4108*2d1d418eSSumit Saxena 			__func__);
4109*2d1d418eSSumit Saxena 		else
4110*2d1d418eSSumit Saxena 			process_evt_bh = 1;
4111*2d1d418eSSumit Saxena 		break;
4112*2d1d418eSSumit Saxena 	}
4113*2d1d418eSSumit Saxena 
4114*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
4115*2d1d418eSSumit Saxena 	{
4116*2d1d418eSSumit Saxena 		process_evt_bh = 1;
4117*2d1d418eSSumit Saxena 		mpi3mr_devstatuschg_evt_th(sc, event_reply);
4118*2d1d418eSSumit Saxena 		break;
4119*2d1d418eSSumit Saxena 	}
4120*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
4121*2d1d418eSSumit Saxena 	{
4122*2d1d418eSSumit Saxena 		process_evt_bh = 1;
4123*2d1d418eSSumit Saxena 		mpi3mr_sastopochg_evt_th(sc, event_reply);
4124*2d1d418eSSumit Saxena 		break;
4125*2d1d418eSSumit Saxena 	}
4126*2d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
4127*2d1d418eSSumit Saxena 	{
4128*2d1d418eSSumit Saxena 		process_evt_bh = 1;
4129*2d1d418eSSumit Saxena 		mpi3mr_pcietopochg_evt_th(sc, event_reply);
4130*2d1d418eSSumit Saxena 		break;
4131*2d1d418eSSumit Saxena 	}
4132*2d1d418eSSumit Saxena 	case MPI3_EVENT_PREPARE_FOR_RESET:
4133*2d1d418eSSumit Saxena 	{
4134*2d1d418eSSumit Saxena 		mpi3mr_preparereset_evt_th(sc, event_reply);
4135*2d1d418eSSumit Saxena 		ack_req = 0;
4136*2d1d418eSSumit Saxena 		break;
4137*2d1d418eSSumit Saxena 	}
4138*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
4139*2d1d418eSSumit Saxena 	case MPI3_EVENT_LOG_DATA:
4140*2d1d418eSSumit Saxena 	{
4141*2d1d418eSSumit Saxena 		process_evt_bh = 1;
4142*2d1d418eSSumit Saxena 		break;
4143*2d1d418eSSumit Saxena 	}
4144*2d1d418eSSumit Saxena 	case MPI3_EVENT_ENERGY_PACK_CHANGE:
4145*2d1d418eSSumit Saxena 	{
4146*2d1d418eSSumit Saxena 		mpi3mr_energypackchg_evt_th(sc, event_reply);
4147*2d1d418eSSumit Saxena 		break;
4148*2d1d418eSSumit Saxena 	}
4149*2d1d418eSSumit Saxena 	case MPI3_EVENT_CABLE_MGMT:
4150*2d1d418eSSumit Saxena 	{
4151*2d1d418eSSumit Saxena 		mpi3mr_cablemgmt_evt_th(sc, event_reply);
4152*2d1d418eSSumit Saxena 		break;
4153*2d1d418eSSumit Saxena 	}
4154*2d1d418eSSumit Saxena 
4155*2d1d418eSSumit Saxena 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
4156*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_DISCOVERY:
4157*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
4158*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
4159*2d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_ENUMERATION:
4160*2d1d418eSSumit Saxena 		break;
4161*2d1d418eSSumit Saxena 	default:
4162*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "%s :Event 0x%02x is not handled by driver\n",
4163*2d1d418eSSumit Saxena 		    __func__, evt_type);
4164*2d1d418eSSumit Saxena 		break;
4165*2d1d418eSSumit Saxena 	}
4166*2d1d418eSSumit Saxena 
4167*2d1d418eSSumit Saxena 	if (process_evt_bh || ack_req) {
4168*2d1d418eSSumit Saxena 		fw_event = malloc(sizeof(struct mpi3mr_fw_event_work), M_MPI3MR,
4169*2d1d418eSSumit Saxena 		     M_ZERO|M_NOWAIT);
4170*2d1d418eSSumit Saxena 
4171*2d1d418eSSumit Saxena 		if (!fw_event) {
4172*2d1d418eSSumit Saxena 			printf("%s: allocate failed for fw_event\n", __func__);
4173*2d1d418eSSumit Saxena 			return;
4174*2d1d418eSSumit Saxena 		}
4175*2d1d418eSSumit Saxena 
4176*2d1d418eSSumit Saxena 		sz = le16toh(event_reply->EventDataLength) * 4;
4177*2d1d418eSSumit Saxena 		fw_event->event_data = malloc(sz, M_MPI3MR, M_ZERO|M_NOWAIT);
4178*2d1d418eSSumit Saxena 
4179*2d1d418eSSumit Saxena 		if (!fw_event->event_data) {
4180*2d1d418eSSumit Saxena 			printf("%s: allocate failed for event_data\n", __func__);
4181*2d1d418eSSumit Saxena 			free(fw_event, M_MPI3MR);
4182*2d1d418eSSumit Saxena 			return;
4183*2d1d418eSSumit Saxena 		}
4184*2d1d418eSSumit Saxena 
4185*2d1d418eSSumit Saxena 		bcopy(event_reply->EventData, fw_event->event_data, sz);
4186*2d1d418eSSumit Saxena 		fw_event->event = event_reply->Event;
4187*2d1d418eSSumit Saxena 		if ((event_reply->Event == MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
4188*2d1d418eSSumit Saxena 		    event_reply->Event == MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST ||
4189*2d1d418eSSumit Saxena 		    event_reply->Event == MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE ) &&
4190*2d1d418eSSumit Saxena 		    sc->track_mapping_events)
4191*2d1d418eSSumit Saxena 			sc->pending_map_events++;
4192*2d1d418eSSumit Saxena 
4193*2d1d418eSSumit Saxena 		/*
4194*2d1d418eSSumit Saxena 		 * Events should be processed after Port enable is completed.
4195*2d1d418eSSumit Saxena 		 */
4196*2d1d418eSSumit Saxena 		if ((event_reply->Event == MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
4197*2d1d418eSSumit Saxena 		    event_reply->Event == MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST ) &&
4198*2d1d418eSSumit Saxena 		    !(sc->mpi3mr_flags & MPI3MR_FLAGS_PORT_ENABLE_DONE))
4199*2d1d418eSSumit Saxena 			mpi3mr_startup_increment(sc->cam_sc);
4200*2d1d418eSSumit Saxena 
4201*2d1d418eSSumit Saxena 		fw_event->send_ack = ack_req;
4202*2d1d418eSSumit Saxena 		fw_event->event_context = le32toh(event_reply->EventContext);
4203*2d1d418eSSumit Saxena 		fw_event->event_data_size = sz;
4204*2d1d418eSSumit Saxena 		fw_event->process_event = process_evt_bh;
4205*2d1d418eSSumit Saxena 
4206*2d1d418eSSumit Saxena 		mtx_lock(&sc->fwevt_lock);
4207*2d1d418eSSumit Saxena 		TAILQ_INSERT_TAIL(&sc->cam_sc->ev_queue, fw_event, ev_link);
4208*2d1d418eSSumit Saxena 		taskqueue_enqueue(sc->cam_sc->ev_tq, &sc->cam_sc->ev_task);
4209*2d1d418eSSumit Saxena 		mtx_unlock(&sc->fwevt_lock);
4210*2d1d418eSSumit Saxena 
4211*2d1d418eSSumit Saxena 	}
4212*2d1d418eSSumit Saxena out:
4213*2d1d418eSSumit Saxena 	return;
4214*2d1d418eSSumit Saxena }
4215*2d1d418eSSumit Saxena 
4216*2d1d418eSSumit Saxena static void mpi3mr_handle_events(struct mpi3mr_softc *sc, uintptr_t data,
4217*2d1d418eSSumit Saxena     Mpi3DefaultReply_t *def_reply)
4218*2d1d418eSSumit Saxena {
4219*2d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply =
4220*2d1d418eSSumit Saxena 		(Mpi3EventNotificationReply_t *)def_reply;
4221*2d1d418eSSumit Saxena 
4222*2d1d418eSSumit Saxena 	sc->change_count = event_reply->IOCChangeCount;
4223*2d1d418eSSumit Saxena 	mpi3mr_display_event_data(sc, event_reply);
4224*2d1d418eSSumit Saxena 
4225*2d1d418eSSumit Saxena 	mpi3mr_process_events(sc, data, event_reply);
4226*2d1d418eSSumit Saxena }
4227*2d1d418eSSumit Saxena 
4228*2d1d418eSSumit Saxena static void mpi3mr_process_admin_reply_desc(struct mpi3mr_softc *sc,
4229*2d1d418eSSumit Saxena     Mpi3DefaultReplyDescriptor_t *reply_desc, U64 *reply_dma)
4230*2d1d418eSSumit Saxena {
4231*2d1d418eSSumit Saxena 	U16 reply_desc_type, host_tag = 0, idx;
4232*2d1d418eSSumit Saxena 	U16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
4233*2d1d418eSSumit Saxena 	U32 ioc_loginfo = 0;
4234*2d1d418eSSumit Saxena 	Mpi3StatusReplyDescriptor_t *status_desc;
4235*2d1d418eSSumit Saxena 	Mpi3AddressReplyDescriptor_t *addr_desc;
4236*2d1d418eSSumit Saxena 	Mpi3SuccessReplyDescriptor_t *success_desc;
4237*2d1d418eSSumit Saxena 	Mpi3DefaultReply_t *def_reply = NULL;
4238*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdptr = NULL;
4239*2d1d418eSSumit Saxena 	Mpi3SCSIIOReply_t *scsi_reply;
4240*2d1d418eSSumit Saxena 	U8 *sense_buf = NULL;
4241*2d1d418eSSumit Saxena 
4242*2d1d418eSSumit Saxena 	*reply_dma = 0;
4243*2d1d418eSSumit Saxena 	reply_desc_type = reply_desc->ReplyFlags &
4244*2d1d418eSSumit Saxena 			    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
4245*2d1d418eSSumit Saxena 	switch (reply_desc_type) {
4246*2d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
4247*2d1d418eSSumit Saxena 		status_desc = (Mpi3StatusReplyDescriptor_t *)reply_desc;
4248*2d1d418eSSumit Saxena 		host_tag = status_desc->HostTag;
4249*2d1d418eSSumit Saxena 		ioc_status = status_desc->IOCStatus;
4250*2d1d418eSSumit Saxena 		if (ioc_status &
4251*2d1d418eSSumit Saxena 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
4252*2d1d418eSSumit Saxena 			ioc_loginfo = status_desc->IOCLogInfo;
4253*2d1d418eSSumit Saxena 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
4254*2d1d418eSSumit Saxena 		break;
4255*2d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
4256*2d1d418eSSumit Saxena 		addr_desc = (Mpi3AddressReplyDescriptor_t *)reply_desc;
4257*2d1d418eSSumit Saxena 		*reply_dma = addr_desc->ReplyFrameAddress;
4258*2d1d418eSSumit Saxena 		def_reply = mpi3mr_get_reply_virt_addr(sc, *reply_dma);
4259*2d1d418eSSumit Saxena 		if (def_reply == NULL)
4260*2d1d418eSSumit Saxena 			goto out;
4261*2d1d418eSSumit Saxena 		host_tag = def_reply->HostTag;
4262*2d1d418eSSumit Saxena 		ioc_status = def_reply->IOCStatus;
4263*2d1d418eSSumit Saxena 		if (ioc_status &
4264*2d1d418eSSumit Saxena 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
4265*2d1d418eSSumit Saxena 			ioc_loginfo = def_reply->IOCLogInfo;
4266*2d1d418eSSumit Saxena 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
4267*2d1d418eSSumit Saxena 		if (def_reply->Function == MPI3_FUNCTION_SCSI_IO) {
4268*2d1d418eSSumit Saxena 			scsi_reply = (Mpi3SCSIIOReply_t *)def_reply;
4269*2d1d418eSSumit Saxena 			sense_buf = mpi3mr_get_sensebuf_virt_addr(sc,
4270*2d1d418eSSumit Saxena 			    scsi_reply->SenseDataBufferAddress);
4271*2d1d418eSSumit Saxena 		}
4272*2d1d418eSSumit Saxena 		break;
4273*2d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
4274*2d1d418eSSumit Saxena 		success_desc = (Mpi3SuccessReplyDescriptor_t *)reply_desc;
4275*2d1d418eSSumit Saxena 		host_tag = success_desc->HostTag;
4276*2d1d418eSSumit Saxena 		break;
4277*2d1d418eSSumit Saxena 	default:
4278*2d1d418eSSumit Saxena 		break;
4279*2d1d418eSSumit Saxena 	}
4280*2d1d418eSSumit Saxena 	switch (host_tag) {
4281*2d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_INITCMDS:
4282*2d1d418eSSumit Saxena 		cmdptr = &sc->init_cmds;
4283*2d1d418eSSumit Saxena 		break;
4284*2d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_IOCTLCMDS:
4285*2d1d418eSSumit Saxena 		cmdptr = &sc->ioctl_cmds;
4286*2d1d418eSSumit Saxena 		break;
4287*2d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_TMS:
4288*2d1d418eSSumit Saxena 		cmdptr = &sc->host_tm_cmds;
4289*2d1d418eSSumit Saxena 		wakeup((void *)&sc->tm_chan);
4290*2d1d418eSSumit Saxena 		break;
4291*2d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_PELABORT:
4292*2d1d418eSSumit Saxena 		cmdptr = &sc->pel_abort_cmd;
4293*2d1d418eSSumit Saxena 		break;
4294*2d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_PELWAIT:
4295*2d1d418eSSumit Saxena 		cmdptr = &sc->pel_cmds;
4296*2d1d418eSSumit Saxena 		break;
4297*2d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_INVALID:
4298*2d1d418eSSumit Saxena 		if (def_reply && def_reply->Function ==
4299*2d1d418eSSumit Saxena 		    MPI3_FUNCTION_EVENT_NOTIFICATION)
4300*2d1d418eSSumit Saxena 			mpi3mr_handle_events(sc, *reply_dma ,def_reply);
4301*2d1d418eSSumit Saxena 	default:
4302*2d1d418eSSumit Saxena 		break;
4303*2d1d418eSSumit Saxena 	}
4304*2d1d418eSSumit Saxena 
4305*2d1d418eSSumit Saxena 	if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN &&
4306*2d1d418eSSumit Saxena 	    host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX ) {
4307*2d1d418eSSumit Saxena 		idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
4308*2d1d418eSSumit Saxena 		cmdptr = &sc->dev_rmhs_cmds[idx];
4309*2d1d418eSSumit Saxena 	}
4310*2d1d418eSSumit Saxena 
4311*2d1d418eSSumit Saxena 	if (host_tag >= MPI3MR_HOSTTAG_EVTACKCMD_MIN &&
4312*2d1d418eSSumit Saxena 	    host_tag <= MPI3MR_HOSTTAG_EVTACKCMD_MAX) {
4313*2d1d418eSSumit Saxena 		idx = host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
4314*2d1d418eSSumit Saxena 		cmdptr = &sc->evtack_cmds[idx];
4315*2d1d418eSSumit Saxena 	}
4316*2d1d418eSSumit Saxena 
4317*2d1d418eSSumit Saxena 	if (cmdptr) {
4318*2d1d418eSSumit Saxena 		if (cmdptr->state & MPI3MR_CMD_PENDING) {
4319*2d1d418eSSumit Saxena 			cmdptr->state |= MPI3MR_CMD_COMPLETE;
4320*2d1d418eSSumit Saxena 			cmdptr->ioc_loginfo = ioc_loginfo;
4321*2d1d418eSSumit Saxena 			cmdptr->ioc_status = ioc_status;
4322*2d1d418eSSumit Saxena 			cmdptr->state &= ~MPI3MR_CMD_PENDING;
4323*2d1d418eSSumit Saxena 			if (def_reply) {
4324*2d1d418eSSumit Saxena 				cmdptr->state |= MPI3MR_CMD_REPLYVALID;
4325*2d1d418eSSumit Saxena 				memcpy((U8 *)cmdptr->reply, (U8 *)def_reply,
4326*2d1d418eSSumit Saxena 				    sc->reply_sz);
4327*2d1d418eSSumit Saxena 			}
4328*2d1d418eSSumit Saxena 			if (sense_buf && cmdptr->sensebuf) {
4329*2d1d418eSSumit Saxena 				cmdptr->is_senseprst = 1;
4330*2d1d418eSSumit Saxena 				memcpy(cmdptr->sensebuf, sense_buf,
4331*2d1d418eSSumit Saxena 				    MPI3MR_SENSEBUF_SZ);
4332*2d1d418eSSumit Saxena 			}
4333*2d1d418eSSumit Saxena 			if (cmdptr->is_waiting) {
4334*2d1d418eSSumit Saxena 				complete(&cmdptr->completion);
4335*2d1d418eSSumit Saxena 				cmdptr->is_waiting = 0;
4336*2d1d418eSSumit Saxena 			} else if (cmdptr->callback)
4337*2d1d418eSSumit Saxena 				cmdptr->callback(sc, cmdptr);
4338*2d1d418eSSumit Saxena 		}
4339*2d1d418eSSumit Saxena 	}
4340*2d1d418eSSumit Saxena out:
4341*2d1d418eSSumit Saxena 	if (sense_buf != NULL)
4342*2d1d418eSSumit Saxena 		mpi3mr_repost_sense_buf(sc,
4343*2d1d418eSSumit Saxena 		    scsi_reply->SenseDataBufferAddress);
4344*2d1d418eSSumit Saxena 	return;
4345*2d1d418eSSumit Saxena }
4346*2d1d418eSSumit Saxena 
4347*2d1d418eSSumit Saxena /*
4348*2d1d418eSSumit Saxena  * mpi3mr_complete_admin_cmd:	ISR routine for admin commands
4349*2d1d418eSSumit Saxena  * @sc:				Adapter's soft instance
4350*2d1d418eSSumit Saxena  *
4351*2d1d418eSSumit Saxena  * This function processes admin command completions.
4352*2d1d418eSSumit Saxena  */
4353*2d1d418eSSumit Saxena static int mpi3mr_complete_admin_cmd(struct mpi3mr_softc *sc)
4354*2d1d418eSSumit Saxena {
4355*2d1d418eSSumit Saxena 	U32 exp_phase = sc->admin_reply_ephase;
4356*2d1d418eSSumit Saxena 	U32 adm_reply_ci = sc->admin_reply_ci;
4357*2d1d418eSSumit Saxena 	U32 num_adm_reply = 0;
4358*2d1d418eSSumit Saxena 	U64 reply_dma = 0;
4359*2d1d418eSSumit Saxena 	Mpi3DefaultReplyDescriptor_t *reply_desc;
4360*2d1d418eSSumit Saxena 
4361*2d1d418eSSumit Saxena 	mtx_lock_spin(&sc->admin_reply_lock);
4362*2d1d418eSSumit Saxena 	if (sc->admin_in_use == false) {
4363*2d1d418eSSumit Saxena 		sc->admin_in_use = true;
4364*2d1d418eSSumit Saxena 		mtx_unlock_spin(&sc->admin_reply_lock);
4365*2d1d418eSSumit Saxena 	} else {
4366*2d1d418eSSumit Saxena 		mtx_unlock_spin(&sc->admin_reply_lock);
4367*2d1d418eSSumit Saxena 		return 0;
4368*2d1d418eSSumit Saxena 	}
4369*2d1d418eSSumit Saxena 
4370*2d1d418eSSumit Saxena 	reply_desc = (Mpi3DefaultReplyDescriptor_t *)sc->admin_reply +
4371*2d1d418eSSumit Saxena 		adm_reply_ci;
4372*2d1d418eSSumit Saxena 
4373*2d1d418eSSumit Saxena 	if ((reply_desc->ReplyFlags &
4374*2d1d418eSSumit Saxena 	     MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
4375*2d1d418eSSumit Saxena 		mtx_lock_spin(&sc->admin_reply_lock);
4376*2d1d418eSSumit Saxena 		sc->admin_in_use = false;
4377*2d1d418eSSumit Saxena 		mtx_unlock_spin(&sc->admin_reply_lock);
4378*2d1d418eSSumit Saxena 		return 0;
4379*2d1d418eSSumit Saxena 	}
4380*2d1d418eSSumit Saxena 
4381*2d1d418eSSumit Saxena 	do {
4382*2d1d418eSSumit Saxena 		sc->admin_req_ci = reply_desc->RequestQueueCI;
4383*2d1d418eSSumit Saxena 		mpi3mr_process_admin_reply_desc(sc, reply_desc, &reply_dma);
4384*2d1d418eSSumit Saxena 		if (reply_dma)
4385*2d1d418eSSumit Saxena 			mpi3mr_repost_reply_buf(sc, reply_dma);
4386*2d1d418eSSumit Saxena 		num_adm_reply++;
4387*2d1d418eSSumit Saxena 		if (++adm_reply_ci == sc->num_admin_replies) {
4388*2d1d418eSSumit Saxena 			adm_reply_ci = 0;
4389*2d1d418eSSumit Saxena 			exp_phase ^= 1;
4390*2d1d418eSSumit Saxena 		}
4391*2d1d418eSSumit Saxena 		reply_desc =
4392*2d1d418eSSumit Saxena 			(Mpi3DefaultReplyDescriptor_t *)sc->admin_reply +
4393*2d1d418eSSumit Saxena 			    adm_reply_ci;
4394*2d1d418eSSumit Saxena 		if ((reply_desc->ReplyFlags &
4395*2d1d418eSSumit Saxena 		     MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
4396*2d1d418eSSumit Saxena 			break;
4397*2d1d418eSSumit Saxena 	} while (1);
4398*2d1d418eSSumit Saxena 
4399*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REPLY_Q_CI_OFFSET, adm_reply_ci);
4400*2d1d418eSSumit Saxena 	sc->admin_reply_ci = adm_reply_ci;
4401*2d1d418eSSumit Saxena 	sc->admin_reply_ephase = exp_phase;
4402*2d1d418eSSumit Saxena 	mtx_lock_spin(&sc->admin_reply_lock);
4403*2d1d418eSSumit Saxena 	sc->admin_in_use = false;
4404*2d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->admin_reply_lock);
4405*2d1d418eSSumit Saxena 	return num_adm_reply;
4406*2d1d418eSSumit Saxena }
4407*2d1d418eSSumit Saxena 
4408*2d1d418eSSumit Saxena static void
4409*2d1d418eSSumit Saxena mpi3mr_cmd_done(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cmd)
4410*2d1d418eSSumit Saxena {
4411*2d1d418eSSumit Saxena 	mpi3mr_unmap_request(sc, cmd);
4412*2d1d418eSSumit Saxena 
4413*2d1d418eSSumit Saxena 	mtx_lock(&sc->mpi3mr_mtx);
4414*2d1d418eSSumit Saxena 	if (cmd->callout_owner) {
4415*2d1d418eSSumit Saxena 		callout_stop(&cmd->callout);
4416*2d1d418eSSumit Saxena 		cmd->callout_owner = false;
4417*2d1d418eSSumit Saxena 	}
4418*2d1d418eSSumit Saxena 
4419*2d1d418eSSumit Saxena 	if (sc->unrecoverable)
4420*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(cmd->ccb, CAM_DEV_NOT_THERE);
4421*2d1d418eSSumit Saxena 
4422*2d1d418eSSumit Saxena 	xpt_done(cmd->ccb);
4423*2d1d418eSSumit Saxena 	cmd->ccb = NULL;
4424*2d1d418eSSumit Saxena 	mtx_unlock(&sc->mpi3mr_mtx);
4425*2d1d418eSSumit Saxena 	mpi3mr_release_command(cmd);
4426*2d1d418eSSumit Saxena }
4427*2d1d418eSSumit Saxena 
4428*2d1d418eSSumit Saxena void mpi3mr_process_op_reply_desc(struct mpi3mr_softc *sc,
4429*2d1d418eSSumit Saxena     Mpi3DefaultReplyDescriptor_t *reply_desc, U64 *reply_dma)
4430*2d1d418eSSumit Saxena {
4431*2d1d418eSSumit Saxena 	U16 reply_desc_type, host_tag = 0;
4432*2d1d418eSSumit Saxena 	U16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
4433*2d1d418eSSumit Saxena 	U32 ioc_loginfo = 0;
4434*2d1d418eSSumit Saxena 	Mpi3StatusReplyDescriptor_t *status_desc = NULL;
4435*2d1d418eSSumit Saxena 	Mpi3AddressReplyDescriptor_t *addr_desc = NULL;
4436*2d1d418eSSumit Saxena 	Mpi3SuccessReplyDescriptor_t *success_desc = NULL;
4437*2d1d418eSSumit Saxena 	Mpi3SCSIIOReply_t *scsi_reply = NULL;
4438*2d1d418eSSumit Saxena 	U8 *sense_buf = NULL;
4439*2d1d418eSSumit Saxena 	U8 scsi_state = 0, scsi_status = 0, sense_state = 0;
4440*2d1d418eSSumit Saxena 	U32 xfer_count = 0, sense_count =0, resp_data = 0;
4441*2d1d418eSSumit Saxena 	struct mpi3mr_cmd *cm = NULL;
4442*2d1d418eSSumit Saxena 	union ccb *ccb;
4443*2d1d418eSSumit Saxena 	struct ccb_scsiio *csio;
4444*2d1d418eSSumit Saxena 	struct mpi3mr_cam_softc *cam_sc;
4445*2d1d418eSSumit Saxena 	U32 target_id;
4446*2d1d418eSSumit Saxena 	U8 *scsi_cdb;
4447*2d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
4448*2d1d418eSSumit Saxena 	U32 ioc_pend_data_len = 0, tg_pend_data_len = 0, data_len_blks = 0;
4449*2d1d418eSSumit Saxena 	struct mpi3mr_throttle_group_info *tg = NULL;
4450*2d1d418eSSumit Saxena 	U8 throttle_enabled_dev = 0;
4451*2d1d418eSSumit Saxena 	static int ratelimit;
4452*2d1d418eSSumit Saxena 
4453*2d1d418eSSumit Saxena 	*reply_dma = 0;
4454*2d1d418eSSumit Saxena 	reply_desc_type = reply_desc->ReplyFlags &
4455*2d1d418eSSumit Saxena 			    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
4456*2d1d418eSSumit Saxena 	switch (reply_desc_type) {
4457*2d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
4458*2d1d418eSSumit Saxena 		status_desc = (Mpi3StatusReplyDescriptor_t *)reply_desc;
4459*2d1d418eSSumit Saxena 		host_tag = status_desc->HostTag;
4460*2d1d418eSSumit Saxena 		ioc_status = status_desc->IOCStatus;
4461*2d1d418eSSumit Saxena 		if (ioc_status &
4462*2d1d418eSSumit Saxena 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
4463*2d1d418eSSumit Saxena 			ioc_loginfo = status_desc->IOCLogInfo;
4464*2d1d418eSSumit Saxena 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
4465*2d1d418eSSumit Saxena 		break;
4466*2d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
4467*2d1d418eSSumit Saxena 		addr_desc = (Mpi3AddressReplyDescriptor_t *)reply_desc;
4468*2d1d418eSSumit Saxena 		*reply_dma = addr_desc->ReplyFrameAddress;
4469*2d1d418eSSumit Saxena 		scsi_reply = mpi3mr_get_reply_virt_addr(sc,
4470*2d1d418eSSumit Saxena 		    *reply_dma);
4471*2d1d418eSSumit Saxena 		if (scsi_reply == NULL) {
4472*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "scsi_reply is NULL, "
4473*2d1d418eSSumit Saxena 			    "this shouldn't happen, reply_desc: %p\n",
4474*2d1d418eSSumit Saxena 			    reply_desc);
4475*2d1d418eSSumit Saxena 			goto out;
4476*2d1d418eSSumit Saxena 		}
4477*2d1d418eSSumit Saxena 
4478*2d1d418eSSumit Saxena 		host_tag = scsi_reply->HostTag;
4479*2d1d418eSSumit Saxena 		ioc_status = scsi_reply->IOCStatus;
4480*2d1d418eSSumit Saxena 		scsi_status = scsi_reply->SCSIStatus;
4481*2d1d418eSSumit Saxena 		scsi_state = scsi_reply->SCSIState;
4482*2d1d418eSSumit Saxena 		sense_state = (scsi_state & MPI3_SCSI_STATE_SENSE_MASK);
4483*2d1d418eSSumit Saxena 		xfer_count = scsi_reply->TransferCount;
4484*2d1d418eSSumit Saxena 		sense_count = scsi_reply->SenseCount;
4485*2d1d418eSSumit Saxena 		resp_data = scsi_reply->ResponseData;
4486*2d1d418eSSumit Saxena 		sense_buf = mpi3mr_get_sensebuf_virt_addr(sc,
4487*2d1d418eSSumit Saxena 		    scsi_reply->SenseDataBufferAddress);
4488*2d1d418eSSumit Saxena 		if (ioc_status &
4489*2d1d418eSSumit Saxena 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
4490*2d1d418eSSumit Saxena 			ioc_loginfo = scsi_reply->IOCLogInfo;
4491*2d1d418eSSumit Saxena 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
4492*2d1d418eSSumit Saxena 		if (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY)
4493*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Ran out of sense buffers\n");
4494*2d1d418eSSumit Saxena 
4495*2d1d418eSSumit Saxena 		break;
4496*2d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
4497*2d1d418eSSumit Saxena 		success_desc = (Mpi3SuccessReplyDescriptor_t *)reply_desc;
4498*2d1d418eSSumit Saxena 		host_tag = success_desc->HostTag;
4499*2d1d418eSSumit Saxena 
4500*2d1d418eSSumit Saxena 	default:
4501*2d1d418eSSumit Saxena 		break;
4502*2d1d418eSSumit Saxena 	}
4503*2d1d418eSSumit Saxena 
4504*2d1d418eSSumit Saxena 	cm = sc->cmd_list[host_tag];
4505*2d1d418eSSumit Saxena 
4506*2d1d418eSSumit Saxena 	if (cm->state == MPI3MR_CMD_STATE_FREE)
4507*2d1d418eSSumit Saxena 		goto out;
4508*2d1d418eSSumit Saxena 
4509*2d1d418eSSumit Saxena 	cam_sc = sc->cam_sc;
4510*2d1d418eSSumit Saxena 	ccb = cm->ccb;
4511*2d1d418eSSumit Saxena 	csio = &ccb->csio;
4512*2d1d418eSSumit Saxena 	target_id = csio->ccb_h.target_id;
4513*2d1d418eSSumit Saxena 
4514*2d1d418eSSumit Saxena 	scsi_cdb = scsiio_cdb_ptr(csio);
4515*2d1d418eSSumit Saxena 
4516*2d1d418eSSumit Saxena 	target = mpi3mr_find_target_by_per_id(cam_sc, target_id);
4517*2d1d418eSSumit Saxena 	if (sc->iot_enable) {
4518*2d1d418eSSumit Saxena 		data_len_blks = csio->dxfer_len >> 9;
4519*2d1d418eSSumit Saxena 
4520*2d1d418eSSumit Saxena 		if (target) {
4521*2d1d418eSSumit Saxena 			tg = target->throttle_group;
4522*2d1d418eSSumit Saxena 			throttle_enabled_dev =
4523*2d1d418eSSumit Saxena 				target->io_throttle_enabled;
4524*2d1d418eSSumit Saxena 		}
4525*2d1d418eSSumit Saxena 
4526*2d1d418eSSumit Saxena 		if ((data_len_blks >= sc->io_throttle_data_length) &&
4527*2d1d418eSSumit Saxena 		     throttle_enabled_dev) {
4528*2d1d418eSSumit Saxena 			mpi3mr_atomic_sub(&sc->pend_large_data_sz, data_len_blks);
4529*2d1d418eSSumit Saxena 			ioc_pend_data_len = mpi3mr_atomic_read(
4530*2d1d418eSSumit Saxena 			    &sc->pend_large_data_sz);
4531*2d1d418eSSumit Saxena 			if (tg) {
4532*2d1d418eSSumit Saxena 				mpi3mr_atomic_sub(&tg->pend_large_data_sz,
4533*2d1d418eSSumit Saxena 					data_len_blks);
4534*2d1d418eSSumit Saxena 				tg_pend_data_len = mpi3mr_atomic_read(&tg->pend_large_data_sz);
4535*2d1d418eSSumit Saxena 				if (ratelimit % 1000) {
4536*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
4537*2d1d418eSSumit Saxena 						"large vd_io completion persist_id(%d), handle(0x%04x), data_len(%d),"
4538*2d1d418eSSumit Saxena 						"ioc_pending(%d), tg_pending(%d), ioc_low(%d), tg_low(%d)\n",
4539*2d1d418eSSumit Saxena 						    target->per_id,
4540*2d1d418eSSumit Saxena 						    target->dev_handle,
4541*2d1d418eSSumit Saxena 						    data_len_blks, ioc_pend_data_len,
4542*2d1d418eSSumit Saxena 						    tg_pend_data_len,
4543*2d1d418eSSumit Saxena 						    sc->io_throttle_low,
4544*2d1d418eSSumit Saxena 						    tg->low);
4545*2d1d418eSSumit Saxena 					ratelimit++;
4546*2d1d418eSSumit Saxena 				}
4547*2d1d418eSSumit Saxena 				if (tg->io_divert  && ((ioc_pend_data_len <=
4548*2d1d418eSSumit Saxena 				    sc->io_throttle_low) &&
4549*2d1d418eSSumit Saxena 				    (tg_pend_data_len <= tg->low))) {
4550*2d1d418eSSumit Saxena 					tg->io_divert = 0;
4551*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
4552*2d1d418eSSumit Saxena 						"VD: Coming out of divert perst_id(%d) tg_id(%d)\n",
4553*2d1d418eSSumit Saxena 						target->per_id, tg->id);
4554*2d1d418eSSumit Saxena 					mpi3mr_set_io_divert_for_all_vd_in_tg(
4555*2d1d418eSSumit Saxena 					    sc, tg, 0);
4556*2d1d418eSSumit Saxena 				}
4557*2d1d418eSSumit Saxena 			} else {
4558*2d1d418eSSumit Saxena 				if (ratelimit % 1000) {
4559*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
4560*2d1d418eSSumit Saxena 					    "large pd_io completion persist_id(%d), handle(0x%04x), data_len(%d), ioc_pending(%d), ioc_low(%d)\n",
4561*2d1d418eSSumit Saxena 					    target->per_id,
4562*2d1d418eSSumit Saxena 					    target->dev_handle,
4563*2d1d418eSSumit Saxena 					    data_len_blks, ioc_pend_data_len,
4564*2d1d418eSSumit Saxena 					    sc->io_throttle_low);
4565*2d1d418eSSumit Saxena 					ratelimit++;
4566*2d1d418eSSumit Saxena 				}
4567*2d1d418eSSumit Saxena 
4568*2d1d418eSSumit Saxena 				if (ioc_pend_data_len <= sc->io_throttle_low) {
4569*2d1d418eSSumit Saxena 					target->io_divert = 0;
4570*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
4571*2d1d418eSSumit Saxena 						"PD: Coming out of divert perst_id(%d)\n",
4572*2d1d418eSSumit Saxena 						target->per_id);
4573*2d1d418eSSumit Saxena 				}
4574*2d1d418eSSumit Saxena 			}
4575*2d1d418eSSumit Saxena 
4576*2d1d418eSSumit Saxena 			} else if (target->io_divert) {
4577*2d1d418eSSumit Saxena 			ioc_pend_data_len = mpi3mr_atomic_read(&sc->pend_large_data_sz);
4578*2d1d418eSSumit Saxena 			if (!tg) {
4579*2d1d418eSSumit Saxena 				if (ratelimit % 1000) {
4580*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
4581*2d1d418eSSumit Saxena 					    "pd_io completion persist_id(%d), handle(0x%04x), data_len(%d), ioc_pending(%d), ioc_low(%d)\n",
4582*2d1d418eSSumit Saxena 					    target->per_id,
4583*2d1d418eSSumit Saxena 					    target->dev_handle,
4584*2d1d418eSSumit Saxena 					    data_len_blks, ioc_pend_data_len,
4585*2d1d418eSSumit Saxena 					    sc->io_throttle_low);
4586*2d1d418eSSumit Saxena 					ratelimit++;
4587*2d1d418eSSumit Saxena 				}
4588*2d1d418eSSumit Saxena 
4589*2d1d418eSSumit Saxena 				if ( ioc_pend_data_len <= sc->io_throttle_low) {
4590*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
4591*2d1d418eSSumit Saxena 						"PD: Coming out of divert perst_id(%d)\n",
4592*2d1d418eSSumit Saxena 						target->per_id);
4593*2d1d418eSSumit Saxena 					target->io_divert = 0;
4594*2d1d418eSSumit Saxena 				}
4595*2d1d418eSSumit Saxena 
4596*2d1d418eSSumit Saxena 			} else if (ioc_pend_data_len <= sc->io_throttle_low) {
4597*2d1d418eSSumit Saxena 				tg_pend_data_len = mpi3mr_atomic_read(&tg->pend_large_data_sz);
4598*2d1d418eSSumit Saxena 				if (ratelimit % 1000) {
4599*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
4600*2d1d418eSSumit Saxena 						"vd_io completion persist_id(%d), handle(0x%04x), data_len(%d),"
4601*2d1d418eSSumit Saxena 						"ioc_pending(%d), tg_pending(%d), ioc_low(%d), tg_low(%d)\n",
4602*2d1d418eSSumit Saxena 						    target->per_id,
4603*2d1d418eSSumit Saxena 						    target->dev_handle,
4604*2d1d418eSSumit Saxena 						    data_len_blks, ioc_pend_data_len,
4605*2d1d418eSSumit Saxena 						    tg_pend_data_len,
4606*2d1d418eSSumit Saxena 						    sc->io_throttle_low,
4607*2d1d418eSSumit Saxena 						    tg->low);
4608*2d1d418eSSumit Saxena 					ratelimit++;
4609*2d1d418eSSumit Saxena 				}
4610*2d1d418eSSumit Saxena 				if (tg->io_divert  && (tg_pend_data_len <= tg->low)) {
4611*2d1d418eSSumit Saxena 					tg->io_divert = 0;
4612*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
4613*2d1d418eSSumit Saxena 						"VD: Coming out of divert perst_id(%d) tg_id(%d)\n",
4614*2d1d418eSSumit Saxena 						target->per_id, tg->id);
4615*2d1d418eSSumit Saxena 					mpi3mr_set_io_divert_for_all_vd_in_tg(
4616*2d1d418eSSumit Saxena 					    sc, tg, 0);
4617*2d1d418eSSumit Saxena 				}
4618*2d1d418eSSumit Saxena 
4619*2d1d418eSSumit Saxena 			}
4620*2d1d418eSSumit Saxena 		}
4621*2d1d418eSSumit Saxena 	}
4622*2d1d418eSSumit Saxena 
4623*2d1d418eSSumit Saxena 	if (success_desc) {
4624*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
4625*2d1d418eSSumit Saxena 		goto out_success;
4626*2d1d418eSSumit Saxena 	}
4627*2d1d418eSSumit Saxena 
4628*2d1d418eSSumit Saxena 	if (ioc_status == MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN
4629*2d1d418eSSumit Saxena 	    && xfer_count == 0 && (scsi_status == MPI3_SCSI_STATUS_BUSY ||
4630*2d1d418eSSumit Saxena 	    scsi_status == MPI3_SCSI_STATUS_RESERVATION_CONFLICT ||
4631*2d1d418eSSumit Saxena 	    scsi_status == MPI3_SCSI_STATUS_TASK_SET_FULL))
4632*2d1d418eSSumit Saxena 		ioc_status = MPI3_IOCSTATUS_SUCCESS;
4633*2d1d418eSSumit Saxena 
4634*2d1d418eSSumit Saxena 	if ((sense_state == MPI3_SCSI_STATE_SENSE_VALID) && sense_count
4635*2d1d418eSSumit Saxena 	    && sense_buf) {
4636*2d1d418eSSumit Saxena 		int sense_len, returned_sense_len;
4637*2d1d418eSSumit Saxena 
4638*2d1d418eSSumit Saxena 		returned_sense_len = min(le32toh(sense_count),
4639*2d1d418eSSumit Saxena 		    sizeof(struct scsi_sense_data));
4640*2d1d418eSSumit Saxena 		if (returned_sense_len < csio->sense_len)
4641*2d1d418eSSumit Saxena 			csio->sense_resid = csio->sense_len -
4642*2d1d418eSSumit Saxena 			    returned_sense_len;
4643*2d1d418eSSumit Saxena 		else
4644*2d1d418eSSumit Saxena 			csio->sense_resid = 0;
4645*2d1d418eSSumit Saxena 
4646*2d1d418eSSumit Saxena 		sense_len = min(returned_sense_len,
4647*2d1d418eSSumit Saxena 		    csio->sense_len - csio->sense_resid);
4648*2d1d418eSSumit Saxena 		bzero(&csio->sense_data, sizeof(csio->sense_data));
4649*2d1d418eSSumit Saxena 		bcopy(sense_buf, &csio->sense_data, sense_len);
4650*2d1d418eSSumit Saxena 		ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
4651*2d1d418eSSumit Saxena 	}
4652*2d1d418eSSumit Saxena 
4653*2d1d418eSSumit Saxena 	switch (ioc_status) {
4654*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_BUSY:
4655*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INSUFFICIENT_RESOURCES:
4656*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQUEUE_REQ);
4657*2d1d418eSSumit Saxena 		break;
4658*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
4659*2d1d418eSSumit Saxena 		/*
4660*2d1d418eSSumit Saxena 		 * If devinfo is 0 this will be a volume.  In that case don't
4661*2d1d418eSSumit Saxena 		 * tell CAM that the volume is not there.  We want volumes to
4662*2d1d418eSSumit Saxena 		 * be enumerated until they are deleted/removed, not just
4663*2d1d418eSSumit Saxena 		 * failed.
4664*2d1d418eSSumit Saxena 		 */
4665*2d1d418eSSumit Saxena 		if (cm->targ->devinfo == 0)
4666*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
4667*2d1d418eSSumit Saxena 		else
4668*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
4669*2d1d418eSSumit Saxena 		break;
4670*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_TASK_TERMINATED:
4671*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED:
4672*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_EXT_TERMINATED:
4673*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_SCSI_BUSY);
4674*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_TRACE,
4675*2d1d418eSSumit Saxena 		    "func: %s line:%d tgt %u Hosttag %u loginfo %x\n",
4676*2d1d418eSSumit Saxena 		    __func__, __LINE__,
4677*2d1d418eSSumit Saxena 		    target_id, cm->hosttag,
4678*2d1d418eSSumit Saxena 		    le32toh(scsi_reply->IOCLogInfo));
4679*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_TRACE,
4680*2d1d418eSSumit Saxena 		    "SCSIStatus %x SCSIState %x xfercount %u\n",
4681*2d1d418eSSumit Saxena 		    scsi_reply->SCSIStatus, scsi_reply->SCSIState,
4682*2d1d418eSSumit Saxena 		    le32toh(xfer_count));
4683*2d1d418eSSumit Saxena 		break;
4684*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_DATA_OVERRUN:
4685*2d1d418eSSumit Saxena 		/* resid is ignored for this condition */
4686*2d1d418eSSumit Saxena 		csio->resid = 0;
4687*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_DATA_RUN_ERR);
4688*2d1d418eSSumit Saxena 		break;
4689*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN:
4690*2d1d418eSSumit Saxena 		csio->resid = cm->length - le32toh(xfer_count);
4691*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR:
4692*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SUCCESS:
4693*2d1d418eSSumit Saxena 		if ((scsi_reply->IOCStatus & MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK) ==
4694*2d1d418eSSumit Saxena 		    MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR)
4695*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_XINFO, "func: %s line: %d recovered error\n",  __func__, __LINE__);
4696*2d1d418eSSumit Saxena 
4697*2d1d418eSSumit Saxena 		/* Completion failed at the transport level. */
4698*2d1d418eSSumit Saxena 		if (scsi_reply->SCSIState & (MPI3_SCSI_STATE_NO_SCSI_STATUS |
4699*2d1d418eSSumit Saxena 		    MPI3_SCSI_STATE_TERMINATED)) {
4700*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
4701*2d1d418eSSumit Saxena 			break;
4702*2d1d418eSSumit Saxena 		}
4703*2d1d418eSSumit Saxena 
4704*2d1d418eSSumit Saxena 		/* In a modern packetized environment, an autosense failure
4705*2d1d418eSSumit Saxena 		 * implies that there's not much else that can be done to
4706*2d1d418eSSumit Saxena 		 * recover the command.
4707*2d1d418eSSumit Saxena 		 */
4708*2d1d418eSSumit Saxena 		if (scsi_reply->SCSIState & MPI3_SCSI_STATE_SENSE_VALID) {
4709*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_AUTOSENSE_FAIL);
4710*2d1d418eSSumit Saxena 			break;
4711*2d1d418eSSumit Saxena 		}
4712*2d1d418eSSumit Saxena 
4713*2d1d418eSSumit Saxena 		/*
4714*2d1d418eSSumit Saxena 		 * Intentionally override the normal SCSI status reporting
4715*2d1d418eSSumit Saxena 		 * for these two cases.  These are likely to happen in a
4716*2d1d418eSSumit Saxena 		 * multi-initiator environment, and we want to make sure that
4717*2d1d418eSSumit Saxena 		 * CAM retries these commands rather than fail them.
4718*2d1d418eSSumit Saxena 		 */
4719*2d1d418eSSumit Saxena 		if ((scsi_reply->SCSIStatus == MPI3_SCSI_STATUS_COMMAND_TERMINATED) ||
4720*2d1d418eSSumit Saxena 		    (scsi_reply->SCSIStatus == MPI3_SCSI_STATUS_TASK_ABORTED)) {
4721*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_REQ_ABORTED);
4722*2d1d418eSSumit Saxena 			break;
4723*2d1d418eSSumit Saxena 		}
4724*2d1d418eSSumit Saxena 
4725*2d1d418eSSumit Saxena 		/* Handle normal status and sense */
4726*2d1d418eSSumit Saxena 		csio->scsi_status = scsi_reply->SCSIStatus;
4727*2d1d418eSSumit Saxena 		if (scsi_reply->SCSIStatus == MPI3_SCSI_STATUS_GOOD)
4728*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
4729*2d1d418eSSumit Saxena 		else
4730*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_SCSI_STATUS_ERROR);
4731*2d1d418eSSumit Saxena 
4732*2d1d418eSSumit Saxena 		if (scsi_reply->SCSIState & MPI3_SCSI_STATE_SENSE_VALID) {
4733*2d1d418eSSumit Saxena 			int sense_len, returned_sense_len;
4734*2d1d418eSSumit Saxena 
4735*2d1d418eSSumit Saxena 			returned_sense_len = min(le32toh(scsi_reply->SenseCount),
4736*2d1d418eSSumit Saxena 			    sizeof(struct scsi_sense_data));
4737*2d1d418eSSumit Saxena 			if (returned_sense_len < csio->sense_len)
4738*2d1d418eSSumit Saxena 				csio->sense_resid = csio->sense_len -
4739*2d1d418eSSumit Saxena 				    returned_sense_len;
4740*2d1d418eSSumit Saxena 			else
4741*2d1d418eSSumit Saxena 				csio->sense_resid = 0;
4742*2d1d418eSSumit Saxena 
4743*2d1d418eSSumit Saxena 			sense_len = min(returned_sense_len,
4744*2d1d418eSSumit Saxena 			    csio->sense_len - csio->sense_resid);
4745*2d1d418eSSumit Saxena 			bzero(&csio->sense_data, sizeof(csio->sense_data));
4746*2d1d418eSSumit Saxena 			bcopy(cm->sense, &csio->sense_data, sense_len);
4747*2d1d418eSSumit Saxena 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
4748*2d1d418eSSumit Saxena 		}
4749*2d1d418eSSumit Saxena 
4750*2d1d418eSSumit Saxena 		break;
4751*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INVALID_SGL:
4752*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_UNREC_HBA_ERROR);
4753*2d1d418eSSumit Saxena 		break;
4754*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_EEDP_GUARD_ERROR:
4755*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR:
4756*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR:
4757*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_PROTOCOL_ERROR:
4758*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INVALID_FUNCTION:
4759*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INTERNAL_ERROR:
4760*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INVALID_FIELD:
4761*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INVALID_STATE:
4762*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_IO_DATA_ERROR:
4763*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
4764*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INSUFFICIENT_POWER:
4765*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
4766*2d1d418eSSumit Saxena 	default:
4767*2d1d418eSSumit Saxena 		csio->resid = cm->length;
4768*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
4769*2d1d418eSSumit Saxena 		break;
4770*2d1d418eSSumit Saxena 	}
4771*2d1d418eSSumit Saxena 
4772*2d1d418eSSumit Saxena out_success:
4773*2d1d418eSSumit Saxena 	if (mpi3mr_get_ccbstatus(ccb) != CAM_REQ_CMP) {
4774*2d1d418eSSumit Saxena 		ccb->ccb_h.status |= CAM_DEV_QFRZN;
4775*2d1d418eSSumit Saxena 		xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
4776*2d1d418eSSumit Saxena 	}
4777*2d1d418eSSumit Saxena 
4778*2d1d418eSSumit Saxena 	mpi3mr_atomic_dec(&cm->targ->outstanding);
4779*2d1d418eSSumit Saxena 	mpi3mr_cmd_done(sc, cm);
4780*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_TRACE, "Completion IO path :"
4781*2d1d418eSSumit Saxena 		" cdb[0]: %x targetid: 0x%x SMID: %x ioc_status: 0x%x ioc_loginfo: 0x%x scsi_status: 0x%x "
4782*2d1d418eSSumit Saxena 		"scsi_state: 0x%x response_data: 0x%x\n", scsi_cdb[0], target_id, host_tag,
4783*2d1d418eSSumit Saxena 		ioc_status, ioc_loginfo, scsi_status, scsi_state, resp_data);
4784*2d1d418eSSumit Saxena 	mpi3mr_atomic_dec(&sc->fw_outstanding);
4785*2d1d418eSSumit Saxena out:
4786*2d1d418eSSumit Saxena 
4787*2d1d418eSSumit Saxena 	if (sense_buf)
4788*2d1d418eSSumit Saxena 		mpi3mr_repost_sense_buf(sc,
4789*2d1d418eSSumit Saxena 		    scsi_reply->SenseDataBufferAddress);
4790*2d1d418eSSumit Saxena 	return;
4791*2d1d418eSSumit Saxena }
4792*2d1d418eSSumit Saxena 
4793*2d1d418eSSumit Saxena /*
4794*2d1d418eSSumit Saxena  * mpi3mr_complete_io_cmd:	ISR routine for IO commands
4795*2d1d418eSSumit Saxena  * @sc:				Adapter's soft instance
4796*2d1d418eSSumit Saxena  * @irq_ctx:			Driver's internal per IRQ structure
4797*2d1d418eSSumit Saxena  *
4798*2d1d418eSSumit Saxena  * This function processes IO command completions.
4799*2d1d418eSSumit Saxena  */
4800*2d1d418eSSumit Saxena int mpi3mr_complete_io_cmd(struct mpi3mr_softc *sc,
4801*2d1d418eSSumit Saxena     struct mpi3mr_irq_context *irq_ctx)
4802*2d1d418eSSumit Saxena {
4803*2d1d418eSSumit Saxena 	struct mpi3mr_op_reply_queue *op_reply_q = irq_ctx->op_reply_q;
4804*2d1d418eSSumit Saxena 	U32 exp_phase = op_reply_q->ephase;
4805*2d1d418eSSumit Saxena 	U32 reply_ci = op_reply_q->ci;
4806*2d1d418eSSumit Saxena 	U32 num_op_replies = 0;
4807*2d1d418eSSumit Saxena 	U64 reply_dma = 0;
4808*2d1d418eSSumit Saxena 	Mpi3DefaultReplyDescriptor_t *reply_desc;
4809*2d1d418eSSumit Saxena 	U16 req_qid = 0;
4810*2d1d418eSSumit Saxena 
4811*2d1d418eSSumit Saxena 	mtx_lock_spin(&op_reply_q->q_lock);
4812*2d1d418eSSumit Saxena 	if (op_reply_q->in_use == false) {
4813*2d1d418eSSumit Saxena 		op_reply_q->in_use = true;
4814*2d1d418eSSumit Saxena 		mtx_unlock_spin(&op_reply_q->q_lock);
4815*2d1d418eSSumit Saxena 	} else {
4816*2d1d418eSSumit Saxena 		mtx_unlock_spin(&op_reply_q->q_lock);
4817*2d1d418eSSumit Saxena 		return 0;
4818*2d1d418eSSumit Saxena 	}
4819*2d1d418eSSumit Saxena 
4820*2d1d418eSSumit Saxena 	reply_desc = (Mpi3DefaultReplyDescriptor_t *)op_reply_q->q_base + reply_ci;
4821*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_TRACE, "[QID:%d]:reply_desc: (%pa) reply_ci: %x"
4822*2d1d418eSSumit Saxena 		" reply_desc->ReplyFlags: 0x%x\n"
4823*2d1d418eSSumit Saxena 		"reply_q_base_phys: %#016jx reply_q_base: (%pa) exp_phase: %x\n",
4824*2d1d418eSSumit Saxena 		op_reply_q->qid, reply_desc, reply_ci, reply_desc->ReplyFlags, op_reply_q->q_base_phys,
4825*2d1d418eSSumit Saxena 		op_reply_q->q_base, exp_phase);
4826*2d1d418eSSumit Saxena 
4827*2d1d418eSSumit Saxena 	if (((reply_desc->ReplyFlags &
4828*2d1d418eSSumit Saxena 	     MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) || !op_reply_q->qid) {
4829*2d1d418eSSumit Saxena 		mtx_lock_spin(&op_reply_q->q_lock);
4830*2d1d418eSSumit Saxena 		op_reply_q->in_use = false;
4831*2d1d418eSSumit Saxena 		mtx_unlock_spin(&op_reply_q->q_lock);
4832*2d1d418eSSumit Saxena 		return 0;
4833*2d1d418eSSumit Saxena 	}
4834*2d1d418eSSumit Saxena 
4835*2d1d418eSSumit Saxena 	do {
4836*2d1d418eSSumit Saxena 		req_qid = reply_desc->RequestQueueID;
4837*2d1d418eSSumit Saxena 		sc->op_req_q[req_qid - 1].ci =
4838*2d1d418eSSumit Saxena 		    reply_desc->RequestQueueCI;
4839*2d1d418eSSumit Saxena 
4840*2d1d418eSSumit Saxena 		mpi3mr_process_op_reply_desc(sc, reply_desc, &reply_dma);
4841*2d1d418eSSumit Saxena 		mpi3mr_atomic_dec(&op_reply_q->pend_ios);
4842*2d1d418eSSumit Saxena 		if (reply_dma)
4843*2d1d418eSSumit Saxena 			mpi3mr_repost_reply_buf(sc, reply_dma);
4844*2d1d418eSSumit Saxena 		num_op_replies++;
4845*2d1d418eSSumit Saxena 		if (++reply_ci == op_reply_q->num_replies) {
4846*2d1d418eSSumit Saxena 			reply_ci = 0;
4847*2d1d418eSSumit Saxena 			exp_phase ^= 1;
4848*2d1d418eSSumit Saxena 		}
4849*2d1d418eSSumit Saxena 		reply_desc =
4850*2d1d418eSSumit Saxena 		    (Mpi3DefaultReplyDescriptor_t *)op_reply_q->q_base + reply_ci;
4851*2d1d418eSSumit Saxena 		if ((reply_desc->ReplyFlags &
4852*2d1d418eSSumit Saxena 		     MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
4853*2d1d418eSSumit Saxena 			break;
4854*2d1d418eSSumit Saxena 	} while (1);
4855*2d1d418eSSumit Saxena 
4856*2d1d418eSSumit Saxena 
4857*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_OPER_REPLY_Q_N_CI_OFFSET(op_reply_q->qid), reply_ci);
4858*2d1d418eSSumit Saxena 	op_reply_q->ci = reply_ci;
4859*2d1d418eSSumit Saxena 	op_reply_q->ephase = exp_phase;
4860*2d1d418eSSumit Saxena 	mtx_lock_spin(&op_reply_q->q_lock);
4861*2d1d418eSSumit Saxena 	op_reply_q->in_use = false;
4862*2d1d418eSSumit Saxena 	mtx_unlock_spin(&op_reply_q->q_lock);
4863*2d1d418eSSumit Saxena 	return num_op_replies;
4864*2d1d418eSSumit Saxena }
4865*2d1d418eSSumit Saxena 
4866*2d1d418eSSumit Saxena /*
4867*2d1d418eSSumit Saxena  * mpi3mr_isr:			Primary ISR function
4868*2d1d418eSSumit Saxena  * privdata:			Driver's internal per IRQ structure
4869*2d1d418eSSumit Saxena  *
4870*2d1d418eSSumit Saxena  * This is driver's primary ISR function which is being called whenever any admin/IO
4871*2d1d418eSSumit Saxena  * command completion.
4872*2d1d418eSSumit Saxena  */
4873*2d1d418eSSumit Saxena void mpi3mr_isr(void *privdata)
4874*2d1d418eSSumit Saxena {
4875*2d1d418eSSumit Saxena 	struct mpi3mr_irq_context *irq_ctx = (struct mpi3mr_irq_context *)privdata;
4876*2d1d418eSSumit Saxena 	struct mpi3mr_softc *sc = irq_ctx->sc;
4877*2d1d418eSSumit Saxena 	U16 msi_idx;
4878*2d1d418eSSumit Saxena 
4879*2d1d418eSSumit Saxena 	if (!irq_ctx)
4880*2d1d418eSSumit Saxena 		return;
4881*2d1d418eSSumit Saxena 
4882*2d1d418eSSumit Saxena 	msi_idx = irq_ctx->msix_index;
4883*2d1d418eSSumit Saxena 
4884*2d1d418eSSumit Saxena 	if (!sc->intr_enabled)
4885*2d1d418eSSumit Saxena 		return;
4886*2d1d418eSSumit Saxena 
4887*2d1d418eSSumit Saxena 	if (!msi_idx)
4888*2d1d418eSSumit Saxena 		mpi3mr_complete_admin_cmd(sc);
4889*2d1d418eSSumit Saxena 
4890*2d1d418eSSumit Saxena 	if (irq_ctx->op_reply_q && irq_ctx->op_reply_q->qid) {
4891*2d1d418eSSumit Saxena 		mpi3mr_complete_io_cmd(sc, irq_ctx);
4892*2d1d418eSSumit Saxena 	}
4893*2d1d418eSSumit Saxena }
4894*2d1d418eSSumit Saxena 
4895*2d1d418eSSumit Saxena /*
4896*2d1d418eSSumit Saxena  * mpi3mr_alloc_requests - Allocates host commands
4897*2d1d418eSSumit Saxena  * @sc: Adapter reference
4898*2d1d418eSSumit Saxena  *
4899*2d1d418eSSumit Saxena  * This function allocates controller supported host commands
4900*2d1d418eSSumit Saxena  *
4901*2d1d418eSSumit Saxena  * Return: 0 on success and proper error codes on failure
4902*2d1d418eSSumit Saxena  */
4903*2d1d418eSSumit Saxena int
4904*2d1d418eSSumit Saxena mpi3mr_alloc_requests(struct mpi3mr_softc *sc)
4905*2d1d418eSSumit Saxena {
4906*2d1d418eSSumit Saxena 	struct mpi3mr_cmd *cmd;
4907*2d1d418eSSumit Saxena 	int i, j, nsegs, ret;
4908*2d1d418eSSumit Saxena 
4909*2d1d418eSSumit Saxena 	nsegs = MPI3MR_SG_DEPTH;
4910*2d1d418eSSumit Saxena 	ret = bus_dma_tag_create( sc->mpi3mr_parent_dmat,    /* parent */
4911*2d1d418eSSumit Saxena 				1, 0,			/* algnmnt, boundary */
4912*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* lowaddr */
4913*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
4914*2d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
4915*2d1d418eSSumit Saxena 				MAXPHYS,/* maxsize */
4916*2d1d418eSSumit Saxena                                 nsegs,			/* nsegments */
4917*2d1d418eSSumit Saxena 				MAXPHYS,/* maxsegsize */
4918*2d1d418eSSumit Saxena                                 BUS_DMA_ALLOCNOW,	/* flags */
4919*2d1d418eSSumit Saxena                                 busdma_lock_mutex,	/* lockfunc */
4920*2d1d418eSSumit Saxena 				&sc->io_lock,	/* lockarg */
4921*2d1d418eSSumit Saxena 				&sc->buffer_dmat);
4922*2d1d418eSSumit Saxena 	if (ret) {
4923*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate buffer DMA tag ret: %d\n", ret);
4924*2d1d418eSSumit Saxena 		return (ENOMEM);
4925*2d1d418eSSumit Saxena         }
4926*2d1d418eSSumit Saxena 
4927*2d1d418eSSumit Saxena 	/*
4928*2d1d418eSSumit Saxena 	 * sc->cmd_list is an array of struct mpi3mr_cmd pointers.
4929*2d1d418eSSumit Saxena 	 * Allocate the dynamic array first and then allocate individual
4930*2d1d418eSSumit Saxena 	 * commands.
4931*2d1d418eSSumit Saxena 	 */
4932*2d1d418eSSumit Saxena 	sc->cmd_list = malloc(sizeof(struct mpi3mr_cmd *) * sc->max_host_ios,
4933*2d1d418eSSumit Saxena 	    M_MPI3MR, M_NOWAIT | M_ZERO);
4934*2d1d418eSSumit Saxena 
4935*2d1d418eSSumit Saxena 	if (!sc->cmd_list) {
4936*2d1d418eSSumit Saxena 		device_printf(sc->mpi3mr_dev, "Cannot alloc memory for mpt_cmd_list.\n");
4937*2d1d418eSSumit Saxena 		return (ENOMEM);
4938*2d1d418eSSumit Saxena 	}
4939*2d1d418eSSumit Saxena 
4940*2d1d418eSSumit Saxena 	for (i = 0; i < sc->max_host_ios; i++) {
4941*2d1d418eSSumit Saxena 		sc->cmd_list[i] = malloc(sizeof(struct mpi3mr_cmd),
4942*2d1d418eSSumit Saxena 		    M_MPI3MR, M_NOWAIT | M_ZERO);
4943*2d1d418eSSumit Saxena 		if (!sc->cmd_list[i]) {
4944*2d1d418eSSumit Saxena 			for (j = 0; j < i; j++)
4945*2d1d418eSSumit Saxena 				free(sc->cmd_list[j], M_MPI3MR);
4946*2d1d418eSSumit Saxena 			free(sc->cmd_list, M_MPI3MR);
4947*2d1d418eSSumit Saxena 			sc->cmd_list = NULL;
4948*2d1d418eSSumit Saxena 			return (ENOMEM);
4949*2d1d418eSSumit Saxena 		}
4950*2d1d418eSSumit Saxena 	}
4951*2d1d418eSSumit Saxena 
4952*2d1d418eSSumit Saxena 	for (i = 1; i < sc->max_host_ios; i++) {
4953*2d1d418eSSumit Saxena 		cmd = sc->cmd_list[i];
4954*2d1d418eSSumit Saxena 		cmd->hosttag = i;
4955*2d1d418eSSumit Saxena 		cmd->sc = sc;
4956*2d1d418eSSumit Saxena 		cmd->state = MPI3MR_CMD_STATE_BUSY;
4957*2d1d418eSSumit Saxena 		callout_init_mtx(&cmd->callout, &sc->mpi3mr_mtx, 0);
4958*2d1d418eSSumit Saxena 		cmd->ccb = NULL;
4959*2d1d418eSSumit Saxena 		TAILQ_INSERT_TAIL(&(sc->cmd_list_head), cmd, next);
4960*2d1d418eSSumit Saxena 		if (bus_dmamap_create(sc->buffer_dmat, 0, &cmd->dmamap))
4961*2d1d418eSSumit Saxena 			return ENOMEM;
4962*2d1d418eSSumit Saxena 	}
4963*2d1d418eSSumit Saxena 	return (0);
4964*2d1d418eSSumit Saxena }
4965*2d1d418eSSumit Saxena 
4966*2d1d418eSSumit Saxena /*
4967*2d1d418eSSumit Saxena  * mpi3mr_get_command:		Get a coomand structure from free command pool
4968*2d1d418eSSumit Saxena  * @sc:				Adapter soft instance
4969*2d1d418eSSumit Saxena  * Return:			MPT command reference
4970*2d1d418eSSumit Saxena  *
4971*2d1d418eSSumit Saxena  * This function returns an MPT command to the caller.
4972*2d1d418eSSumit Saxena  */
4973*2d1d418eSSumit Saxena struct mpi3mr_cmd *
4974*2d1d418eSSumit Saxena mpi3mr_get_command(struct mpi3mr_softc *sc)
4975*2d1d418eSSumit Saxena {
4976*2d1d418eSSumit Saxena 	struct mpi3mr_cmd *cmd = NULL;
4977*2d1d418eSSumit Saxena 
4978*2d1d418eSSumit Saxena 	mtx_lock(&sc->cmd_pool_lock);
4979*2d1d418eSSumit Saxena 	if (!TAILQ_EMPTY(&sc->cmd_list_head)) {
4980*2d1d418eSSumit Saxena 		cmd = TAILQ_FIRST(&sc->cmd_list_head);
4981*2d1d418eSSumit Saxena 		TAILQ_REMOVE(&sc->cmd_list_head, cmd, next);
4982*2d1d418eSSumit Saxena 	} else {
4983*2d1d418eSSumit Saxena 		goto out;
4984*2d1d418eSSumit Saxena 	}
4985*2d1d418eSSumit Saxena 
4986*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_TRACE, "Get command SMID: 0x%x\n", cmd->hosttag);
4987*2d1d418eSSumit Saxena 
4988*2d1d418eSSumit Saxena 	memset((uint8_t *)&cmd->io_request, 0, MPI3MR_AREQ_FRAME_SZ);
4989*2d1d418eSSumit Saxena 	cmd->data_dir = 0;
4990*2d1d418eSSumit Saxena 	cmd->ccb = NULL;
4991*2d1d418eSSumit Saxena 	cmd->targ = NULL;
4992*2d1d418eSSumit Saxena 	cmd->max_segs = 0;
4993*2d1d418eSSumit Saxena 	cmd->lun = 0;
4994*2d1d418eSSumit Saxena 	cmd->state = MPI3MR_CMD_STATE_BUSY;
4995*2d1d418eSSumit Saxena 	cmd->data = NULL;
4996*2d1d418eSSumit Saxena 	cmd->length = 0;
4997*2d1d418eSSumit Saxena 	cmd->out_len = 0;
4998*2d1d418eSSumit Saxena out:
4999*2d1d418eSSumit Saxena 	mtx_unlock(&sc->cmd_pool_lock);
5000*2d1d418eSSumit Saxena 	return cmd;
5001*2d1d418eSSumit Saxena }
5002*2d1d418eSSumit Saxena 
5003*2d1d418eSSumit Saxena /*
5004*2d1d418eSSumit Saxena  * mpi3mr_release_command:	Return a cmd to free command pool
5005*2d1d418eSSumit Saxena  * input:			Command packet for return to free command pool
5006*2d1d418eSSumit Saxena  *
5007*2d1d418eSSumit Saxena  * This function returns an MPT command to the free command list.
5008*2d1d418eSSumit Saxena  */
5009*2d1d418eSSumit Saxena void
5010*2d1d418eSSumit Saxena mpi3mr_release_command(struct mpi3mr_cmd *cmd)
5011*2d1d418eSSumit Saxena {
5012*2d1d418eSSumit Saxena 	struct mpi3mr_softc *sc = cmd->sc;
5013*2d1d418eSSumit Saxena 
5014*2d1d418eSSumit Saxena 	mtx_lock(&sc->cmd_pool_lock);
5015*2d1d418eSSumit Saxena 	TAILQ_INSERT_HEAD(&(sc->cmd_list_head), cmd, next);
5016*2d1d418eSSumit Saxena 	cmd->state = MPI3MR_CMD_STATE_FREE;
5017*2d1d418eSSumit Saxena 	cmd->req_qidx = 0;
5018*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_TRACE, "Release command SMID: 0x%x\n", cmd->hosttag);
5019*2d1d418eSSumit Saxena 	mtx_unlock(&sc->cmd_pool_lock);
5020*2d1d418eSSumit Saxena 
5021*2d1d418eSSumit Saxena 	return;
5022*2d1d418eSSumit Saxena }
5023*2d1d418eSSumit Saxena 
5024*2d1d418eSSumit Saxena  /**
5025*2d1d418eSSumit Saxena  * mpi3mr_free_ioctl_dma_memory - free memory for ioctl dma
5026*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
5027*2d1d418eSSumit Saxena  *
5028*2d1d418eSSumit Saxena  * Free the DMA memory allocated for IOCTL handling purpose.
5029*2d1d418eSSumit Saxena  *
5030*2d1d418eSSumit Saxena  * Return: None
5031*2d1d418eSSumit Saxena  */
5032*2d1d418eSSumit Saxena static void mpi3mr_free_ioctl_dma_memory(struct mpi3mr_softc *sc)
5033*2d1d418eSSumit Saxena {
5034*2d1d418eSSumit Saxena 	U16 i;
5035*2d1d418eSSumit Saxena 	struct dma_memory_desc *mem_desc;
5036*2d1d418eSSumit Saxena 
5037*2d1d418eSSumit Saxena 	for (i=0; i<MPI3MR_NUM_IOCTL_SGE; i++) {
5038*2d1d418eSSumit Saxena 		mem_desc = &sc->ioctl_sge[i];
5039*2d1d418eSSumit Saxena 		if (mem_desc->addr && mem_desc->dma_addr) {
5040*2d1d418eSSumit Saxena 			bus_dmamap_unload(mem_desc->tag, mem_desc->dmamap);
5041*2d1d418eSSumit Saxena 			bus_dmamem_free(mem_desc->tag, mem_desc->addr, mem_desc->dmamap);
5042*2d1d418eSSumit Saxena 			mem_desc->addr = NULL;
5043*2d1d418eSSumit Saxena 			if (mem_desc->tag != NULL)
5044*2d1d418eSSumit Saxena 				bus_dma_tag_destroy(mem_desc->tag);
5045*2d1d418eSSumit Saxena 		}
5046*2d1d418eSSumit Saxena 	}
5047*2d1d418eSSumit Saxena 
5048*2d1d418eSSumit Saxena 	mem_desc = &sc->ioctl_chain_sge;
5049*2d1d418eSSumit Saxena 	if (mem_desc->addr && mem_desc->dma_addr) {
5050*2d1d418eSSumit Saxena 		bus_dmamap_unload(mem_desc->tag, mem_desc->dmamap);
5051*2d1d418eSSumit Saxena 		bus_dmamem_free(mem_desc->tag, mem_desc->addr, mem_desc->dmamap);
5052*2d1d418eSSumit Saxena 		mem_desc->addr = NULL;
5053*2d1d418eSSumit Saxena 		if (mem_desc->tag != NULL)
5054*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(mem_desc->tag);
5055*2d1d418eSSumit Saxena 	}
5056*2d1d418eSSumit Saxena 
5057*2d1d418eSSumit Saxena 	mem_desc = &sc->ioctl_resp_sge;
5058*2d1d418eSSumit Saxena 	if (mem_desc->addr && mem_desc->dma_addr) {
5059*2d1d418eSSumit Saxena 		bus_dmamap_unload(mem_desc->tag, mem_desc->dmamap);
5060*2d1d418eSSumit Saxena 		bus_dmamem_free(mem_desc->tag, mem_desc->addr, mem_desc->dmamap);
5061*2d1d418eSSumit Saxena 		mem_desc->addr = NULL;
5062*2d1d418eSSumit Saxena 		if (mem_desc->tag != NULL)
5063*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(mem_desc->tag);
5064*2d1d418eSSumit Saxena 	}
5065*2d1d418eSSumit Saxena 
5066*2d1d418eSSumit Saxena 	sc->ioctl_sges_allocated = false;
5067*2d1d418eSSumit Saxena }
5068*2d1d418eSSumit Saxena 
5069*2d1d418eSSumit Saxena /**
5070*2d1d418eSSumit Saxena  * mpi3mr_alloc_ioctl_dma_memory - Alloc memory for ioctl dma
5071*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
5072*2d1d418eSSumit Saxena  *
5073*2d1d418eSSumit Saxena  * This function allocates dmaable memory required to handle the
5074*2d1d418eSSumit Saxena  * application issued MPI3 IOCTL requests.
5075*2d1d418eSSumit Saxena  *
5076*2d1d418eSSumit Saxena  * Return: None
5077*2d1d418eSSumit Saxena  */
5078*2d1d418eSSumit Saxena void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_softc *sc)
5079*2d1d418eSSumit Saxena {
5080*2d1d418eSSumit Saxena 	struct dma_memory_desc *mem_desc;
5081*2d1d418eSSumit Saxena 	U16 i;
5082*2d1d418eSSumit Saxena 
5083*2d1d418eSSumit Saxena 	for (i=0; i<MPI3MR_NUM_IOCTL_SGE; i++) {
5084*2d1d418eSSumit Saxena 		mem_desc = &sc->ioctl_sge[i];
5085*2d1d418eSSumit Saxena 		mem_desc->size = MPI3MR_IOCTL_SGE_SIZE;
5086*2d1d418eSSumit Saxena 
5087*2d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
5088*2d1d418eSSumit Saxena 					4, 0,			/* algnmnt, boundary */
5089*2d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
5090*2d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR,	/* highaddr */
5091*2d1d418eSSumit Saxena 					NULL, NULL,		/* filter, filterarg */
5092*2d1d418eSSumit Saxena 					mem_desc->size,		/* maxsize */
5093*2d1d418eSSumit Saxena 					1,			/* nsegments */
5094*2d1d418eSSumit Saxena 					mem_desc->size,		/* maxsegsize */
5095*2d1d418eSSumit Saxena 					0,			/* flags */
5096*2d1d418eSSumit Saxena 					NULL, NULL,		/* lockfunc, lockarg */
5097*2d1d418eSSumit Saxena 					&mem_desc->tag)) {
5098*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
5099*2d1d418eSSumit Saxena 			goto out_failed;
5100*2d1d418eSSumit Saxena 		}
5101*2d1d418eSSumit Saxena 
5102*2d1d418eSSumit Saxena 		if (bus_dmamem_alloc(mem_desc->tag, (void **)&mem_desc->addr,
5103*2d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &mem_desc->dmamap)) {
5104*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
5105*2d1d418eSSumit Saxena 			goto out_failed;
5106*2d1d418eSSumit Saxena 		}
5107*2d1d418eSSumit Saxena 		bzero(mem_desc->addr, mem_desc->size);
5108*2d1d418eSSumit Saxena 		bus_dmamap_load(mem_desc->tag, mem_desc->dmamap, mem_desc->addr, mem_desc->size,
5109*2d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &mem_desc->dma_addr, 0);
5110*2d1d418eSSumit Saxena 
5111*2d1d418eSSumit Saxena 		if (!mem_desc->addr)
5112*2d1d418eSSumit Saxena 			goto out_failed;
5113*2d1d418eSSumit Saxena 	}
5114*2d1d418eSSumit Saxena 
5115*2d1d418eSSumit Saxena 	mem_desc = &sc->ioctl_chain_sge;
5116*2d1d418eSSumit Saxena 	mem_desc->size = MPI3MR_4K_PGSZ;
5117*2d1d418eSSumit Saxena 	if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
5118*2d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
5119*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
5120*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
5121*2d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
5122*2d1d418eSSumit Saxena 				mem_desc->size,		/* maxsize */
5123*2d1d418eSSumit Saxena 				1,			/* nsegments */
5124*2d1d418eSSumit Saxena 				mem_desc->size,		/* maxsegsize */
5125*2d1d418eSSumit Saxena 				0,			/* flags */
5126*2d1d418eSSumit Saxena 				NULL, NULL,		/* lockfunc, lockarg */
5127*2d1d418eSSumit Saxena 				&mem_desc->tag)) {
5128*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
5129*2d1d418eSSumit Saxena 		goto out_failed;
5130*2d1d418eSSumit Saxena 	}
5131*2d1d418eSSumit Saxena 
5132*2d1d418eSSumit Saxena 	if (bus_dmamem_alloc(mem_desc->tag, (void **)&mem_desc->addr,
5133*2d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &mem_desc->dmamap)) {
5134*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
5135*2d1d418eSSumit Saxena 		goto out_failed;
5136*2d1d418eSSumit Saxena 	}
5137*2d1d418eSSumit Saxena 	bzero(mem_desc->addr, mem_desc->size);
5138*2d1d418eSSumit Saxena 	bus_dmamap_load(mem_desc->tag, mem_desc->dmamap, mem_desc->addr, mem_desc->size,
5139*2d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &mem_desc->dma_addr, 0);
5140*2d1d418eSSumit Saxena 
5141*2d1d418eSSumit Saxena 	if (!mem_desc->addr)
5142*2d1d418eSSumit Saxena 		goto out_failed;
5143*2d1d418eSSumit Saxena 
5144*2d1d418eSSumit Saxena 	mem_desc = &sc->ioctl_resp_sge;
5145*2d1d418eSSumit Saxena 	mem_desc->size = MPI3MR_4K_PGSZ;
5146*2d1d418eSSumit Saxena 	if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
5147*2d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
5148*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
5149*2d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
5150*2d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
5151*2d1d418eSSumit Saxena 				mem_desc->size,		/* maxsize */
5152*2d1d418eSSumit Saxena 				1,			/* nsegments */
5153*2d1d418eSSumit Saxena 				mem_desc->size,		/* maxsegsize */
5154*2d1d418eSSumit Saxena 				0,			/* flags */
5155*2d1d418eSSumit Saxena 				NULL, NULL,		/* lockfunc, lockarg */
5156*2d1d418eSSumit Saxena 				&mem_desc->tag)) {
5157*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
5158*2d1d418eSSumit Saxena 		goto out_failed;
5159*2d1d418eSSumit Saxena 	}
5160*2d1d418eSSumit Saxena 
5161*2d1d418eSSumit Saxena 	if (bus_dmamem_alloc(mem_desc->tag, (void **)&mem_desc->addr,
5162*2d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &mem_desc->dmamap)) {
5163*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
5164*2d1d418eSSumit Saxena 		goto out_failed;
5165*2d1d418eSSumit Saxena 	}
5166*2d1d418eSSumit Saxena 	bzero(mem_desc->addr, mem_desc->size);
5167*2d1d418eSSumit Saxena 	bus_dmamap_load(mem_desc->tag, mem_desc->dmamap, mem_desc->addr, mem_desc->size,
5168*2d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &mem_desc->dma_addr, 0);
5169*2d1d418eSSumit Saxena 
5170*2d1d418eSSumit Saxena 	if (!mem_desc->addr)
5171*2d1d418eSSumit Saxena 		goto out_failed;
5172*2d1d418eSSumit Saxena 
5173*2d1d418eSSumit Saxena 	sc->ioctl_sges_allocated = true;
5174*2d1d418eSSumit Saxena 
5175*2d1d418eSSumit Saxena 	return;
5176*2d1d418eSSumit Saxena out_failed:
5177*2d1d418eSSumit Saxena 	printf("cannot allocate DMA memory for the mpt commands"
5178*2d1d418eSSumit Saxena 	    "  from the applications, application interface for MPT command is disabled\n");
5179*2d1d418eSSumit Saxena 	mpi3mr_free_ioctl_dma_memory(sc);
5180*2d1d418eSSumit Saxena }
5181*2d1d418eSSumit Saxena 
5182*2d1d418eSSumit Saxena void
5183*2d1d418eSSumit Saxena mpi3mr_destory_mtx(struct mpi3mr_softc *sc)
5184*2d1d418eSSumit Saxena {
5185*2d1d418eSSumit Saxena 	int i;
5186*2d1d418eSSumit Saxena 	struct mpi3mr_op_req_queue *op_req_q;
5187*2d1d418eSSumit Saxena 	struct mpi3mr_op_reply_queue *op_reply_q;
5188*2d1d418eSSumit Saxena 
5189*2d1d418eSSumit Saxena 	if (sc->admin_reply) {
5190*2d1d418eSSumit Saxena 		if (mtx_initialized(&sc->admin_reply_lock))
5191*2d1d418eSSumit Saxena 			mtx_destroy(&sc->admin_reply_lock);
5192*2d1d418eSSumit Saxena 	}
5193*2d1d418eSSumit Saxena 
5194*2d1d418eSSumit Saxena 	if (sc->op_reply_q) {
5195*2d1d418eSSumit Saxena 		for(i = 0; i < sc->num_queues; i++) {
5196*2d1d418eSSumit Saxena 			op_reply_q = sc->op_reply_q + i;
5197*2d1d418eSSumit Saxena 			if (mtx_initialized(&op_reply_q->q_lock))
5198*2d1d418eSSumit Saxena 				mtx_destroy(&op_reply_q->q_lock);
5199*2d1d418eSSumit Saxena 		}
5200*2d1d418eSSumit Saxena 	}
5201*2d1d418eSSumit Saxena 
5202*2d1d418eSSumit Saxena 	if (sc->op_req_q) {
5203*2d1d418eSSumit Saxena 		for(i = 0; i < sc->num_queues; i++) {
5204*2d1d418eSSumit Saxena 			op_req_q = sc->op_req_q + i;
5205*2d1d418eSSumit Saxena 			if (mtx_initialized(&op_req_q->q_lock))
5206*2d1d418eSSumit Saxena 				mtx_destroy(&op_req_q->q_lock);
5207*2d1d418eSSumit Saxena 		}
5208*2d1d418eSSumit Saxena 	}
5209*2d1d418eSSumit Saxena 
5210*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->init_cmds.completion.lock))
5211*2d1d418eSSumit Saxena 		mtx_destroy(&sc->init_cmds.completion.lock);
5212*2d1d418eSSumit Saxena 
5213*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->ioctl_cmds.completion.lock))
5214*2d1d418eSSumit Saxena 		mtx_destroy(&sc->ioctl_cmds.completion.lock);
5215*2d1d418eSSumit Saxena 
5216*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->host_tm_cmds.completion.lock))
5217*2d1d418eSSumit Saxena 		mtx_destroy(&sc->host_tm_cmds.completion.lock);
5218*2d1d418eSSumit Saxena 
5219*2d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
5220*2d1d418eSSumit Saxena 		if (mtx_initialized(&sc->dev_rmhs_cmds[i].completion.lock))
5221*2d1d418eSSumit Saxena 			mtx_destroy(&sc->dev_rmhs_cmds[i].completion.lock);
5222*2d1d418eSSumit Saxena 	}
5223*2d1d418eSSumit Saxena 
5224*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->reset_mutex))
5225*2d1d418eSSumit Saxena 		mtx_destroy(&sc->reset_mutex);
5226*2d1d418eSSumit Saxena 
5227*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->target_lock))
5228*2d1d418eSSumit Saxena 		mtx_destroy(&sc->target_lock);
5229*2d1d418eSSumit Saxena 
5230*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->fwevt_lock))
5231*2d1d418eSSumit Saxena 		mtx_destroy(&sc->fwevt_lock);
5232*2d1d418eSSumit Saxena 
5233*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->cmd_pool_lock))
5234*2d1d418eSSumit Saxena 		mtx_destroy(&sc->cmd_pool_lock);
5235*2d1d418eSSumit Saxena 
5236*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->reply_free_q_lock))
5237*2d1d418eSSumit Saxena 		mtx_destroy(&sc->reply_free_q_lock);
5238*2d1d418eSSumit Saxena 
5239*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->sense_buf_q_lock))
5240*2d1d418eSSumit Saxena 		mtx_destroy(&sc->sense_buf_q_lock);
5241*2d1d418eSSumit Saxena 
5242*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->chain_buf_lock))
5243*2d1d418eSSumit Saxena 		mtx_destroy(&sc->chain_buf_lock);
5244*2d1d418eSSumit Saxena 
5245*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->admin_req_lock))
5246*2d1d418eSSumit Saxena 		mtx_destroy(&sc->admin_req_lock);
5247*2d1d418eSSumit Saxena 
5248*2d1d418eSSumit Saxena 	if (mtx_initialized(&sc->mpi3mr_mtx))
5249*2d1d418eSSumit Saxena 		mtx_destroy(&sc->mpi3mr_mtx);
5250*2d1d418eSSumit Saxena }
5251*2d1d418eSSumit Saxena 
5252*2d1d418eSSumit Saxena /**
5253*2d1d418eSSumit Saxena  * mpi3mr_free_mem - Freeup adapter level data structures
5254*2d1d418eSSumit Saxena  * @sc: Adapter reference
5255*2d1d418eSSumit Saxena  *
5256*2d1d418eSSumit Saxena  * Return: Nothing.
5257*2d1d418eSSumit Saxena  */
5258*2d1d418eSSumit Saxena void
5259*2d1d418eSSumit Saxena mpi3mr_free_mem(struct mpi3mr_softc *sc)
5260*2d1d418eSSumit Saxena {
5261*2d1d418eSSumit Saxena 	int i;
5262*2d1d418eSSumit Saxena 	struct mpi3mr_op_req_queue *op_req_q;
5263*2d1d418eSSumit Saxena 	struct mpi3mr_op_reply_queue *op_reply_q;
5264*2d1d418eSSumit Saxena 	struct mpi3mr_irq_context *irq_ctx;
5265*2d1d418eSSumit Saxena 
5266*2d1d418eSSumit Saxena 	if (sc->cmd_list) {
5267*2d1d418eSSumit Saxena 		for (i = 0; i < sc->max_host_ios; i++) {
5268*2d1d418eSSumit Saxena 			free(sc->cmd_list[i], M_MPI3MR);
5269*2d1d418eSSumit Saxena 		}
5270*2d1d418eSSumit Saxena 		free(sc->cmd_list, M_MPI3MR);
5271*2d1d418eSSumit Saxena 		sc->cmd_list = NULL;
5272*2d1d418eSSumit Saxena 	}
5273*2d1d418eSSumit Saxena 
5274*2d1d418eSSumit Saxena 	if (sc->pel_seq_number && sc->pel_seq_number_dma) {
5275*2d1d418eSSumit Saxena 		bus_dmamap_unload(sc->pel_seq_num_dmatag, sc->pel_seq_num_dmamap);
5276*2d1d418eSSumit Saxena 		bus_dmamem_free(sc->pel_seq_num_dmatag, sc->pel_seq_number, sc->pel_seq_num_dmamap);
5277*2d1d418eSSumit Saxena 		sc->pel_seq_number = NULL;
5278*2d1d418eSSumit Saxena 		if (sc->pel_seq_num_dmatag != NULL)
5279*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->pel_seq_num_dmatag);
5280*2d1d418eSSumit Saxena 	}
5281*2d1d418eSSumit Saxena 
5282*2d1d418eSSumit Saxena 	if (sc->throttle_groups) {
5283*2d1d418eSSumit Saxena 		free(sc->throttle_groups, M_MPI3MR);
5284*2d1d418eSSumit Saxena 		sc->throttle_groups = NULL;
5285*2d1d418eSSumit Saxena 	}
5286*2d1d418eSSumit Saxena 
5287*2d1d418eSSumit Saxena 	/* Free up operational queues*/
5288*2d1d418eSSumit Saxena 	if (sc->op_req_q) {
5289*2d1d418eSSumit Saxena 		for (i = 0; i < sc->num_queues; i++) {
5290*2d1d418eSSumit Saxena 			op_req_q = sc->op_req_q + i;
5291*2d1d418eSSumit Saxena 			if (op_req_q->q_base && op_req_q->q_base_phys) {
5292*2d1d418eSSumit Saxena 				bus_dmamap_unload(op_req_q->q_base_tag, op_req_q->q_base_dmamap);
5293*2d1d418eSSumit Saxena 				bus_dmamem_free(op_req_q->q_base_tag, op_req_q->q_base, op_req_q->q_base_dmamap);
5294*2d1d418eSSumit Saxena 				op_req_q->q_base = NULL;
5295*2d1d418eSSumit Saxena 				if (op_req_q->q_base_tag != NULL)
5296*2d1d418eSSumit Saxena 					bus_dma_tag_destroy(op_req_q->q_base_tag);
5297*2d1d418eSSumit Saxena 			}
5298*2d1d418eSSumit Saxena 		}
5299*2d1d418eSSumit Saxena 		free(sc->op_req_q, M_MPI3MR);
5300*2d1d418eSSumit Saxena 		sc->op_req_q = NULL;
5301*2d1d418eSSumit Saxena 	}
5302*2d1d418eSSumit Saxena 
5303*2d1d418eSSumit Saxena 	if (sc->op_reply_q) {
5304*2d1d418eSSumit Saxena 		for (i = 0; i < sc->num_queues; i++) {
5305*2d1d418eSSumit Saxena 			op_reply_q = sc->op_reply_q + i;
5306*2d1d418eSSumit Saxena 			if (op_reply_q->q_base && op_reply_q->q_base_phys) {
5307*2d1d418eSSumit Saxena 				bus_dmamap_unload(op_reply_q->q_base_tag, op_reply_q->q_base_dmamap);
5308*2d1d418eSSumit Saxena 				bus_dmamem_free(op_reply_q->q_base_tag, op_reply_q->q_base, op_reply_q->q_base_dmamap);
5309*2d1d418eSSumit Saxena 				op_reply_q->q_base = NULL;
5310*2d1d418eSSumit Saxena 				if (op_reply_q->q_base_tag != NULL)
5311*2d1d418eSSumit Saxena 					bus_dma_tag_destroy(op_reply_q->q_base_tag);
5312*2d1d418eSSumit Saxena 			}
5313*2d1d418eSSumit Saxena 		}
5314*2d1d418eSSumit Saxena 		free(sc->op_reply_q, M_MPI3MR);
5315*2d1d418eSSumit Saxena 		sc->op_reply_q = NULL;
5316*2d1d418eSSumit Saxena 	}
5317*2d1d418eSSumit Saxena 
5318*2d1d418eSSumit Saxena 	/* Free up chain buffers*/
5319*2d1d418eSSumit Saxena 	if (sc->chain_sgl_list) {
5320*2d1d418eSSumit Saxena 		for (i = 0; i < sc->chain_buf_count; i++) {
5321*2d1d418eSSumit Saxena 			if (sc->chain_sgl_list[i].buf && sc->chain_sgl_list[i].buf_phys) {
5322*2d1d418eSSumit Saxena 				bus_dmamap_unload(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf_dmamap);
5323*2d1d418eSSumit Saxena 				bus_dmamem_free(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf,
5324*2d1d418eSSumit Saxena 						sc->chain_sgl_list[i].buf_dmamap);
5325*2d1d418eSSumit Saxena 				sc->chain_sgl_list[i].buf = NULL;
5326*2d1d418eSSumit Saxena 			}
5327*2d1d418eSSumit Saxena 		}
5328*2d1d418eSSumit Saxena 		if (sc->chain_sgl_list_tag != NULL)
5329*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->chain_sgl_list_tag);
5330*2d1d418eSSumit Saxena 		free(sc->chain_sgl_list, M_MPI3MR);
5331*2d1d418eSSumit Saxena 		sc->chain_sgl_list = NULL;
5332*2d1d418eSSumit Saxena 	}
5333*2d1d418eSSumit Saxena 
5334*2d1d418eSSumit Saxena 	if (sc->chain_bitmap) {
5335*2d1d418eSSumit Saxena 		free(sc->chain_bitmap, M_MPI3MR);
5336*2d1d418eSSumit Saxena 		sc->chain_bitmap = NULL;
5337*2d1d418eSSumit Saxena 	}
5338*2d1d418eSSumit Saxena 
5339*2d1d418eSSumit Saxena 	for (i = 0; i < sc->msix_count; i++) {
5340*2d1d418eSSumit Saxena 		irq_ctx = sc->irq_ctx + i;
5341*2d1d418eSSumit Saxena 		if (irq_ctx)
5342*2d1d418eSSumit Saxena 			irq_ctx->op_reply_q = NULL;
5343*2d1d418eSSumit Saxena 	}
5344*2d1d418eSSumit Saxena 
5345*2d1d418eSSumit Saxena 	/* Free reply_buf_tag */
5346*2d1d418eSSumit Saxena 	if (sc->reply_buf && sc->reply_buf_phys) {
5347*2d1d418eSSumit Saxena 		bus_dmamap_unload(sc->reply_buf_tag, sc->reply_buf_dmamap);
5348*2d1d418eSSumit Saxena 		bus_dmamem_free(sc->reply_buf_tag, sc->reply_buf,
5349*2d1d418eSSumit Saxena 				sc->reply_buf_dmamap);
5350*2d1d418eSSumit Saxena 		sc->reply_buf = NULL;
5351*2d1d418eSSumit Saxena 		if (sc->reply_buf_tag != NULL)
5352*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->reply_buf_tag);
5353*2d1d418eSSumit Saxena 	}
5354*2d1d418eSSumit Saxena 
5355*2d1d418eSSumit Saxena 	/* Free reply_free_q_tag */
5356*2d1d418eSSumit Saxena 	if (sc->reply_free_q && sc->reply_free_q_phys) {
5357*2d1d418eSSumit Saxena 		bus_dmamap_unload(sc->reply_free_q_tag, sc->reply_free_q_dmamap);
5358*2d1d418eSSumit Saxena 		bus_dmamem_free(sc->reply_free_q_tag, sc->reply_free_q,
5359*2d1d418eSSumit Saxena 				sc->reply_free_q_dmamap);
5360*2d1d418eSSumit Saxena 		sc->reply_free_q = NULL;
5361*2d1d418eSSumit Saxena 		if (sc->reply_free_q_tag != NULL)
5362*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->reply_free_q_tag);
5363*2d1d418eSSumit Saxena 	}
5364*2d1d418eSSumit Saxena 
5365*2d1d418eSSumit Saxena 	/* Free sense_buf_tag */
5366*2d1d418eSSumit Saxena 	if (sc->sense_buf && sc->sense_buf_phys) {
5367*2d1d418eSSumit Saxena 		bus_dmamap_unload(sc->sense_buf_tag, sc->sense_buf_dmamap);
5368*2d1d418eSSumit Saxena 		bus_dmamem_free(sc->sense_buf_tag, sc->sense_buf,
5369*2d1d418eSSumit Saxena 				sc->sense_buf_dmamap);
5370*2d1d418eSSumit Saxena 		sc->sense_buf = NULL;
5371*2d1d418eSSumit Saxena 		if (sc->sense_buf_tag != NULL)
5372*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->sense_buf_tag);
5373*2d1d418eSSumit Saxena 	}
5374*2d1d418eSSumit Saxena 
5375*2d1d418eSSumit Saxena 	/* Free sense_buf_q_tag */
5376*2d1d418eSSumit Saxena 	if (sc->sense_buf_q && sc->sense_buf_q_phys) {
5377*2d1d418eSSumit Saxena 		bus_dmamap_unload(sc->sense_buf_q_tag, sc->sense_buf_q_dmamap);
5378*2d1d418eSSumit Saxena 		bus_dmamem_free(sc->sense_buf_q_tag, sc->sense_buf_q,
5379*2d1d418eSSumit Saxena 				sc->sense_buf_q_dmamap);
5380*2d1d418eSSumit Saxena 		sc->sense_buf_q = NULL;
5381*2d1d418eSSumit Saxena 		if (sc->sense_buf_q_tag != NULL)
5382*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->sense_buf_q_tag);
5383*2d1d418eSSumit Saxena 	}
5384*2d1d418eSSumit Saxena 
5385*2d1d418eSSumit Saxena 	/* Free up internal(non-IO) commands*/
5386*2d1d418eSSumit Saxena 	if (sc->init_cmds.reply) {
5387*2d1d418eSSumit Saxena 		free(sc->init_cmds.reply, M_MPI3MR);
5388*2d1d418eSSumit Saxena 		sc->init_cmds.reply = NULL;
5389*2d1d418eSSumit Saxena 	}
5390*2d1d418eSSumit Saxena 
5391*2d1d418eSSumit Saxena 	if (sc->ioctl_cmds.reply) {
5392*2d1d418eSSumit Saxena 		free(sc->ioctl_cmds.reply, M_MPI3MR);
5393*2d1d418eSSumit Saxena 		sc->ioctl_cmds.reply = NULL;
5394*2d1d418eSSumit Saxena 	}
5395*2d1d418eSSumit Saxena 
5396*2d1d418eSSumit Saxena 	if (sc->pel_cmds.reply) {
5397*2d1d418eSSumit Saxena 		free(sc->pel_cmds.reply, M_MPI3MR);
5398*2d1d418eSSumit Saxena 		sc->pel_cmds.reply = NULL;
5399*2d1d418eSSumit Saxena 	}
5400*2d1d418eSSumit Saxena 
5401*2d1d418eSSumit Saxena 	if (sc->pel_abort_cmd.reply) {
5402*2d1d418eSSumit Saxena 		free(sc->pel_abort_cmd.reply, M_MPI3MR);
5403*2d1d418eSSumit Saxena 		sc->pel_abort_cmd.reply = NULL;
5404*2d1d418eSSumit Saxena 	}
5405*2d1d418eSSumit Saxena 
5406*2d1d418eSSumit Saxena 	if (sc->host_tm_cmds.reply) {
5407*2d1d418eSSumit Saxena 		free(sc->host_tm_cmds.reply, M_MPI3MR);
5408*2d1d418eSSumit Saxena 		sc->host_tm_cmds.reply = NULL;
5409*2d1d418eSSumit Saxena 	}
5410*2d1d418eSSumit Saxena 
5411*2d1d418eSSumit Saxena 	if (sc->log_data_buffer) {
5412*2d1d418eSSumit Saxena 		free(sc->log_data_buffer, M_MPI3MR);
5413*2d1d418eSSumit Saxena 		sc->log_data_buffer = NULL;
5414*2d1d418eSSumit Saxena 	}
5415*2d1d418eSSumit Saxena 
5416*2d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
5417*2d1d418eSSumit Saxena 		if (sc->dev_rmhs_cmds[i].reply) {
5418*2d1d418eSSumit Saxena 			free(sc->dev_rmhs_cmds[i].reply, M_MPI3MR);
5419*2d1d418eSSumit Saxena 			sc->dev_rmhs_cmds[i].reply = NULL;
5420*2d1d418eSSumit Saxena 		}
5421*2d1d418eSSumit Saxena 	}
5422*2d1d418eSSumit Saxena 
5423*2d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
5424*2d1d418eSSumit Saxena 		if (sc->evtack_cmds[i].reply) {
5425*2d1d418eSSumit Saxena 			free(sc->evtack_cmds[i].reply, M_MPI3MR);
5426*2d1d418eSSumit Saxena 			sc->evtack_cmds[i].reply = NULL;
5427*2d1d418eSSumit Saxena 		}
5428*2d1d418eSSumit Saxena 	}
5429*2d1d418eSSumit Saxena 
5430*2d1d418eSSumit Saxena 	if (sc->removepend_bitmap) {
5431*2d1d418eSSumit Saxena 		free(sc->removepend_bitmap, M_MPI3MR);
5432*2d1d418eSSumit Saxena 		sc->removepend_bitmap = NULL;
5433*2d1d418eSSumit Saxena 	}
5434*2d1d418eSSumit Saxena 
5435*2d1d418eSSumit Saxena 	if (sc->devrem_bitmap) {
5436*2d1d418eSSumit Saxena 		free(sc->devrem_bitmap, M_MPI3MR);
5437*2d1d418eSSumit Saxena 		sc->devrem_bitmap = NULL;
5438*2d1d418eSSumit Saxena 	}
5439*2d1d418eSSumit Saxena 
5440*2d1d418eSSumit Saxena 	if (sc->evtack_cmds_bitmap) {
5441*2d1d418eSSumit Saxena 		free(sc->evtack_cmds_bitmap, M_MPI3MR);
5442*2d1d418eSSumit Saxena 		sc->evtack_cmds_bitmap = NULL;
5443*2d1d418eSSumit Saxena 	}
5444*2d1d418eSSumit Saxena 
5445*2d1d418eSSumit Saxena 	/* Free Admin reply*/
5446*2d1d418eSSumit Saxena 	if (sc->admin_reply && sc->admin_reply_phys) {
5447*2d1d418eSSumit Saxena 		bus_dmamap_unload(sc->admin_reply_tag, sc->admin_reply_dmamap);
5448*2d1d418eSSumit Saxena 		bus_dmamem_free(sc->admin_reply_tag, sc->admin_reply,
5449*2d1d418eSSumit Saxena 				sc->admin_reply_dmamap);
5450*2d1d418eSSumit Saxena 		sc->admin_reply = NULL;
5451*2d1d418eSSumit Saxena 		if (sc->admin_reply_tag != NULL)
5452*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->admin_reply_tag);
5453*2d1d418eSSumit Saxena 	}
5454*2d1d418eSSumit Saxena 
5455*2d1d418eSSumit Saxena 	/* Free Admin request*/
5456*2d1d418eSSumit Saxena 	if (sc->admin_req && sc->admin_req_phys) {
5457*2d1d418eSSumit Saxena 		bus_dmamap_unload(sc->admin_req_tag, sc->admin_req_dmamap);
5458*2d1d418eSSumit Saxena 		bus_dmamem_free(sc->admin_req_tag, sc->admin_req,
5459*2d1d418eSSumit Saxena 				sc->admin_req_dmamap);
5460*2d1d418eSSumit Saxena 		sc->admin_req = NULL;
5461*2d1d418eSSumit Saxena 		if (sc->admin_req_tag != NULL)
5462*2d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->admin_req_tag);
5463*2d1d418eSSumit Saxena 	}
5464*2d1d418eSSumit Saxena 	mpi3mr_free_ioctl_dma_memory(sc);
5465*2d1d418eSSumit Saxena 
5466*2d1d418eSSumit Saxena }
5467*2d1d418eSSumit Saxena 
5468*2d1d418eSSumit Saxena /**
5469*2d1d418eSSumit Saxena  * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command
5470*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
5471*2d1d418eSSumit Saxena  * @cmdptr: Internal command tracker
5472*2d1d418eSSumit Saxena  *
5473*2d1d418eSSumit Saxena  * Complete an internal driver commands with state indicating it
5474*2d1d418eSSumit Saxena  * is completed due to reset.
5475*2d1d418eSSumit Saxena  *
5476*2d1d418eSSumit Saxena  * Return: Nothing.
5477*2d1d418eSSumit Saxena  */
5478*2d1d418eSSumit Saxena static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_softc *sc,
5479*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdptr)
5480*2d1d418eSSumit Saxena {
5481*2d1d418eSSumit Saxena 	if (cmdptr->state & MPI3MR_CMD_PENDING) {
5482*2d1d418eSSumit Saxena 		cmdptr->state |= MPI3MR_CMD_RESET;
5483*2d1d418eSSumit Saxena 		cmdptr->state &= ~MPI3MR_CMD_PENDING;
5484*2d1d418eSSumit Saxena 		if (cmdptr->is_waiting) {
5485*2d1d418eSSumit Saxena 			complete(&cmdptr->completion);
5486*2d1d418eSSumit Saxena 			cmdptr->is_waiting = 0;
5487*2d1d418eSSumit Saxena 		} else if (cmdptr->callback)
5488*2d1d418eSSumit Saxena 			cmdptr->callback(sc, cmdptr);
5489*2d1d418eSSumit Saxena 	}
5490*2d1d418eSSumit Saxena }
5491*2d1d418eSSumit Saxena 
5492*2d1d418eSSumit Saxena /**
5493*2d1d418eSSumit Saxena  * mpi3mr_flush_drv_cmds - Flush internal driver commands
5494*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
5495*2d1d418eSSumit Saxena  *
5496*2d1d418eSSumit Saxena  * Flush all internal driver commands post reset
5497*2d1d418eSSumit Saxena  *
5498*2d1d418eSSumit Saxena  * Return: Nothing.
5499*2d1d418eSSumit Saxena  */
5500*2d1d418eSSumit Saxena static void mpi3mr_flush_drv_cmds(struct mpi3mr_softc *sc)
5501*2d1d418eSSumit Saxena {
5502*2d1d418eSSumit Saxena 	int i = 0;
5503*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdptr;
5504*2d1d418eSSumit Saxena 
5505*2d1d418eSSumit Saxena 	cmdptr = &sc->init_cmds;
5506*2d1d418eSSumit Saxena 	mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
5507*2d1d418eSSumit Saxena 
5508*2d1d418eSSumit Saxena 	cmdptr = &sc->ioctl_cmds;
5509*2d1d418eSSumit Saxena 	mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
5510*2d1d418eSSumit Saxena 
5511*2d1d418eSSumit Saxena 	cmdptr = &sc->host_tm_cmds;
5512*2d1d418eSSumit Saxena 	mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
5513*2d1d418eSSumit Saxena 
5514*2d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
5515*2d1d418eSSumit Saxena 		cmdptr = &sc->dev_rmhs_cmds[i];
5516*2d1d418eSSumit Saxena 		mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
5517*2d1d418eSSumit Saxena 	}
5518*2d1d418eSSumit Saxena 
5519*2d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
5520*2d1d418eSSumit Saxena 		cmdptr = &sc->evtack_cmds[i];
5521*2d1d418eSSumit Saxena 		mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
5522*2d1d418eSSumit Saxena 	}
5523*2d1d418eSSumit Saxena 
5524*2d1d418eSSumit Saxena 	cmdptr = &sc->pel_cmds;
5525*2d1d418eSSumit Saxena 	mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
5526*2d1d418eSSumit Saxena 
5527*2d1d418eSSumit Saxena 	cmdptr = &sc->pel_abort_cmd;
5528*2d1d418eSSumit Saxena 	mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
5529*2d1d418eSSumit Saxena }
5530*2d1d418eSSumit Saxena 
5531*2d1d418eSSumit Saxena 
5532*2d1d418eSSumit Saxena /**
5533*2d1d418eSSumit Saxena  * mpi3mr_memset_buffers - memset memory for a controller
5534*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
5535*2d1d418eSSumit Saxena  *
5536*2d1d418eSSumit Saxena  * clear all the memory allocated for a controller, typically
5537*2d1d418eSSumit Saxena  * called post reset to reuse the memory allocated during the
5538*2d1d418eSSumit Saxena  * controller init.
5539*2d1d418eSSumit Saxena  *
5540*2d1d418eSSumit Saxena  * Return: Nothing.
5541*2d1d418eSSumit Saxena  */
5542*2d1d418eSSumit Saxena static void mpi3mr_memset_buffers(struct mpi3mr_softc *sc)
5543*2d1d418eSSumit Saxena {
5544*2d1d418eSSumit Saxena 	U16 i;
5545*2d1d418eSSumit Saxena 	struct mpi3mr_throttle_group_info *tg;
5546*2d1d418eSSumit Saxena 
5547*2d1d418eSSumit Saxena 	memset(sc->admin_req, 0, sc->admin_req_q_sz);
5548*2d1d418eSSumit Saxena 	memset(sc->admin_reply, 0, sc->admin_reply_q_sz);
5549*2d1d418eSSumit Saxena 
5550*2d1d418eSSumit Saxena 	memset(sc->init_cmds.reply, 0, sc->reply_sz);
5551*2d1d418eSSumit Saxena 	memset(sc->ioctl_cmds.reply, 0, sc->reply_sz);
5552*2d1d418eSSumit Saxena 	memset(sc->host_tm_cmds.reply, 0, sc->reply_sz);
5553*2d1d418eSSumit Saxena 	memset(sc->pel_cmds.reply, 0, sc->reply_sz);
5554*2d1d418eSSumit Saxena 	memset(sc->pel_abort_cmd.reply, 0, sc->reply_sz);
5555*2d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
5556*2d1d418eSSumit Saxena 		memset(sc->dev_rmhs_cmds[i].reply, 0, sc->reply_sz);
5557*2d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++)
5558*2d1d418eSSumit Saxena 		memset(sc->evtack_cmds[i].reply, 0, sc->reply_sz);
5559*2d1d418eSSumit Saxena 	memset(sc->removepend_bitmap, 0, sc->dev_handle_bitmap_sz);
5560*2d1d418eSSumit Saxena 	memset(sc->devrem_bitmap, 0, sc->devrem_bitmap_sz);
5561*2d1d418eSSumit Saxena 	memset(sc->evtack_cmds_bitmap, 0, sc->evtack_cmds_bitmap_sz);
5562*2d1d418eSSumit Saxena 
5563*2d1d418eSSumit Saxena 	for (i = 0; i < sc->num_queues; i++) {
5564*2d1d418eSSumit Saxena 		sc->op_reply_q[i].qid = 0;
5565*2d1d418eSSumit Saxena 		sc->op_reply_q[i].ci = 0;
5566*2d1d418eSSumit Saxena 		sc->op_reply_q[i].num_replies = 0;
5567*2d1d418eSSumit Saxena 		sc->op_reply_q[i].ephase = 0;
5568*2d1d418eSSumit Saxena 		mpi3mr_atomic_set(&sc->op_reply_q[i].pend_ios, 0);
5569*2d1d418eSSumit Saxena 		memset(sc->op_reply_q[i].q_base, 0, sc->op_reply_q[i].qsz);
5570*2d1d418eSSumit Saxena 
5571*2d1d418eSSumit Saxena 		sc->op_req_q[i].ci = 0;
5572*2d1d418eSSumit Saxena 		sc->op_req_q[i].pi = 0;
5573*2d1d418eSSumit Saxena 		sc->op_req_q[i].num_reqs = 0;
5574*2d1d418eSSumit Saxena 		sc->op_req_q[i].qid = 0;
5575*2d1d418eSSumit Saxena 		sc->op_req_q[i].reply_qid = 0;
5576*2d1d418eSSumit Saxena 		memset(sc->op_req_q[i].q_base, 0, sc->op_req_q[i].qsz);
5577*2d1d418eSSumit Saxena 	}
5578*2d1d418eSSumit Saxena 
5579*2d1d418eSSumit Saxena 	mpi3mr_atomic_set(&sc->pend_large_data_sz, 0);
5580*2d1d418eSSumit Saxena 	if (sc->throttle_groups) {
5581*2d1d418eSSumit Saxena 		tg = sc->throttle_groups;
5582*2d1d418eSSumit Saxena 		for (i = 0; i < sc->num_io_throttle_group; i++, tg++) {
5583*2d1d418eSSumit Saxena 			tg->id = 0;
5584*2d1d418eSSumit Saxena 			tg->fw_qd = 0;
5585*2d1d418eSSumit Saxena 			tg->modified_qd = 0;
5586*2d1d418eSSumit Saxena 			tg->io_divert= 0;
5587*2d1d418eSSumit Saxena 			tg->high = 0;
5588*2d1d418eSSumit Saxena 			tg->low = 0;
5589*2d1d418eSSumit Saxena 			mpi3mr_atomic_set(&tg->pend_large_data_sz, 0);
5590*2d1d418eSSumit Saxena 		}
5591*2d1d418eSSumit Saxena  	}
5592*2d1d418eSSumit Saxena }
5593*2d1d418eSSumit Saxena 
5594*2d1d418eSSumit Saxena /**
5595*2d1d418eSSumit Saxena  * mpi3mr_invalidate_devhandles -Invalidate device handles
5596*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
5597*2d1d418eSSumit Saxena  *
5598*2d1d418eSSumit Saxena  * Invalidate the device handles in the target device structures
5599*2d1d418eSSumit Saxena  * . Called post reset prior to reinitializing the controller.
5600*2d1d418eSSumit Saxena  *
5601*2d1d418eSSumit Saxena  * Return: Nothing.
5602*2d1d418eSSumit Saxena  */
5603*2d1d418eSSumit Saxena static void mpi3mr_invalidate_devhandles(struct mpi3mr_softc *sc)
5604*2d1d418eSSumit Saxena {
5605*2d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
5606*2d1d418eSSumit Saxena 
5607*2d1d418eSSumit Saxena 	mtx_lock_spin(&sc->target_lock);
5608*2d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) {
5609*2d1d418eSSumit Saxena 		if (target) {
5610*2d1d418eSSumit Saxena 			target->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
5611*2d1d418eSSumit Saxena 			target->io_throttle_enabled = 0;
5612*2d1d418eSSumit Saxena 			target->io_divert = 0;
5613*2d1d418eSSumit Saxena 			target->throttle_group = NULL;
5614*2d1d418eSSumit Saxena 		}
5615*2d1d418eSSumit Saxena 	}
5616*2d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->target_lock);
5617*2d1d418eSSumit Saxena }
5618*2d1d418eSSumit Saxena 
5619*2d1d418eSSumit Saxena /**
5620*2d1d418eSSumit Saxena  * mpi3mr_rfresh_tgtdevs - Refresh target device exposure
5621*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
5622*2d1d418eSSumit Saxena  *
5623*2d1d418eSSumit Saxena  * This is executed post controller reset to identify any
5624*2d1d418eSSumit Saxena  * missing devices during reset and remove from the upper layers
5625*2d1d418eSSumit Saxena  * or expose any newly detected device to the upper layers.
5626*2d1d418eSSumit Saxena  *
5627*2d1d418eSSumit Saxena  * Return: Nothing.
5628*2d1d418eSSumit Saxena  */
5629*2d1d418eSSumit Saxena 
5630*2d1d418eSSumit Saxena static void mpi3mr_rfresh_tgtdevs(struct mpi3mr_softc *sc)
5631*2d1d418eSSumit Saxena {
5632*2d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
5633*2d1d418eSSumit Saxena 	struct mpi3mr_target *target_temp = NULL;
5634*2d1d418eSSumit Saxena 
5635*2d1d418eSSumit Saxena 	TAILQ_FOREACH_SAFE(target, &sc->cam_sc->tgt_list, tgt_next, target_temp) {
5636*2d1d418eSSumit Saxena 		if (target->dev_handle == MPI3MR_INVALID_DEV_HANDLE) {
5637*2d1d418eSSumit Saxena 			if (target->exposed_to_os)
5638*2d1d418eSSumit Saxena 				mpi3mr_remove_device_from_os(sc, target->dev_handle);
5639*2d1d418eSSumit Saxena 			mpi3mr_remove_device_from_list(sc, target, true);
5640*2d1d418eSSumit Saxena 		}
5641*2d1d418eSSumit Saxena 	}
5642*2d1d418eSSumit Saxena 
5643*2d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) {
5644*2d1d418eSSumit Saxena 		if ((target->dev_handle != MPI3MR_INVALID_DEV_HANDLE) &&
5645*2d1d418eSSumit Saxena 		    !target->is_hidden && !target->exposed_to_os) {
5646*2d1d418eSSumit Saxena 			mpi3mr_add_device(sc, target->per_id);
5647*2d1d418eSSumit Saxena 		}
5648*2d1d418eSSumit Saxena 	}
5649*2d1d418eSSumit Saxena 
5650*2d1d418eSSumit Saxena }
5651*2d1d418eSSumit Saxena 
5652*2d1d418eSSumit Saxena static void mpi3mr_flush_io(struct mpi3mr_softc *sc)
5653*2d1d418eSSumit Saxena {
5654*2d1d418eSSumit Saxena 	int i;
5655*2d1d418eSSumit Saxena 	struct mpi3mr_cmd *cmd = NULL;
5656*2d1d418eSSumit Saxena 	union ccb *ccb = NULL;
5657*2d1d418eSSumit Saxena 
5658*2d1d418eSSumit Saxena 	for (i = 0; i < sc->max_host_ios; i++) {
5659*2d1d418eSSumit Saxena 		cmd = sc->cmd_list[i];
5660*2d1d418eSSumit Saxena 
5661*2d1d418eSSumit Saxena 		if (cmd && cmd->ccb) {
5662*2d1d418eSSumit Saxena 			if (cmd->callout_owner) {
5663*2d1d418eSSumit Saxena 				ccb = (union ccb *)(cmd->ccb);
5664*2d1d418eSSumit Saxena 				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
5665*2d1d418eSSumit Saxena 				mpi3mr_cmd_done(sc, cmd);
5666*2d1d418eSSumit Saxena 			} else {
5667*2d1d418eSSumit Saxena 				cmd->ccb = NULL;
5668*2d1d418eSSumit Saxena 				mpi3mr_release_command(cmd);
5669*2d1d418eSSumit Saxena 			}
5670*2d1d418eSSumit Saxena 		}
5671*2d1d418eSSumit Saxena 	}
5672*2d1d418eSSumit Saxena }
5673*2d1d418eSSumit Saxena /**
5674*2d1d418eSSumit Saxena  * mpi3mr_clear_reset_history - Clear reset history
5675*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
5676*2d1d418eSSumit Saxena  *
5677*2d1d418eSSumit Saxena  * Write the reset history bit in IOC Status to clear the bit,
5678*2d1d418eSSumit Saxena  * if it is already set.
5679*2d1d418eSSumit Saxena  *
5680*2d1d418eSSumit Saxena  * Return: Nothing.
5681*2d1d418eSSumit Saxena  */
5682*2d1d418eSSumit Saxena static inline void mpi3mr_clear_reset_history(struct mpi3mr_softc *sc)
5683*2d1d418eSSumit Saxena {
5684*2d1d418eSSumit Saxena 	U32 ioc_status;
5685*2d1d418eSSumit Saxena 
5686*2d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
5687*2d1d418eSSumit Saxena 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
5688*2d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_STATUS_OFFSET, ioc_status);
5689*2d1d418eSSumit Saxena }
5690*2d1d418eSSumit Saxena 
5691*2d1d418eSSumit Saxena /**
5692*2d1d418eSSumit Saxena  * mpi3mr_set_diagsave - Set diag save bit for snapdump
5693*2d1d418eSSumit Saxena  * @sc: Adapter reference
5694*2d1d418eSSumit Saxena  *
5695*2d1d418eSSumit Saxena  * Set diag save bit in IOC configuration register to enable
5696*2d1d418eSSumit Saxena  * snapdump.
5697*2d1d418eSSumit Saxena  *
5698*2d1d418eSSumit Saxena  * Return: Nothing.
5699*2d1d418eSSumit Saxena  */
5700*2d1d418eSSumit Saxena static inline void mpi3mr_set_diagsave(struct mpi3mr_softc *sc)
5701*2d1d418eSSumit Saxena {
5702*2d1d418eSSumit Saxena 	U32 ioc_config;
5703*2d1d418eSSumit Saxena 
5704*2d1d418eSSumit Saxena 	ioc_config =
5705*2d1d418eSSumit Saxena 	    mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
5706*2d1d418eSSumit Saxena 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE;
5707*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
5708*2d1d418eSSumit Saxena }
5709*2d1d418eSSumit Saxena 
5710*2d1d418eSSumit Saxena /**
5711*2d1d418eSSumit Saxena  * mpi3mr_issue_reset - Issue reset to the controller
5712*2d1d418eSSumit Saxena  * @sc: Adapter reference
5713*2d1d418eSSumit Saxena  * @reset_type: Reset type
5714*2d1d418eSSumit Saxena  * @reset_reason: Reset reason code
5715*2d1d418eSSumit Saxena  *
5716*2d1d418eSSumit Saxena  * Unlock the host diagnostic registers and write the specific
5717*2d1d418eSSumit Saxena  * reset type to that, wait for reset acknowledgement from the
5718*2d1d418eSSumit Saxena  * controller, if the reset is not successful retry for the
5719*2d1d418eSSumit Saxena  * predefined number of times.
5720*2d1d418eSSumit Saxena  *
5721*2d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failure.
5722*2d1d418eSSumit Saxena  */
5723*2d1d418eSSumit Saxena static int mpi3mr_issue_reset(struct mpi3mr_softc *sc, U16 reset_type,
5724*2d1d418eSSumit Saxena 	U32 reset_reason)
5725*2d1d418eSSumit Saxena {
5726*2d1d418eSSumit Saxena 	int retval = -1;
5727*2d1d418eSSumit Saxena 	U8 unlock_retry_count = 0;
5728*2d1d418eSSumit Saxena 	U32 host_diagnostic, ioc_status, ioc_config;
5729*2d1d418eSSumit Saxena 	U32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
5730*2d1d418eSSumit Saxena 
5731*2d1d418eSSumit Saxena 	if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) &&
5732*2d1d418eSSumit Saxena 	    (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT))
5733*2d1d418eSSumit Saxena 		return retval;
5734*2d1d418eSSumit Saxena 	if (sc->unrecoverable)
5735*2d1d418eSSumit Saxena 		return retval;
5736*2d1d418eSSumit Saxena 
5737*2d1d418eSSumit Saxena 	if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) {
5738*2d1d418eSSumit Saxena 		retval = 0;
5739*2d1d418eSSumit Saxena 		return retval;
5740*2d1d418eSSumit Saxena 	}
5741*2d1d418eSSumit Saxena 
5742*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "%s reset due to %s(0x%x)\n",
5743*2d1d418eSSumit Saxena 	    mpi3mr_reset_type_name(reset_type),
5744*2d1d418eSSumit Saxena 	    mpi3mr_reset_rc_name(reset_reason), reset_reason);
5745*2d1d418eSSumit Saxena 
5746*2d1d418eSSumit Saxena 	mpi3mr_clear_reset_history(sc);
5747*2d1d418eSSumit Saxena 	do {
5748*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
5749*2d1d418eSSumit Saxena 		    "Write magic sequence to unlock host diag register (retry=%d)\n",
5750*2d1d418eSSumit Saxena 		    ++unlock_retry_count);
5751*2d1d418eSSumit Saxena 		if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) {
5752*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
5753*2d1d418eSSumit Saxena 			    "%s reset failed! due to host diag register unlock failure"
5754*2d1d418eSSumit Saxena 			    "host_diagnostic(0x%08x)\n", mpi3mr_reset_type_name(reset_type),
5755*2d1d418eSSumit Saxena 			    host_diagnostic);
5756*2d1d418eSSumit Saxena 			sc->unrecoverable = 1;
5757*2d1d418eSSumit Saxena 			return retval;
5758*2d1d418eSSumit Saxena 		}
5759*2d1d418eSSumit Saxena 
5760*2d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
5761*2d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH);
5762*2d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
5763*2d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST);
5764*2d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
5765*2d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND);
5766*2d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
5767*2d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD);
5768*2d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
5769*2d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH);
5770*2d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
5771*2d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH);
5772*2d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
5773*2d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH);
5774*2d1d418eSSumit Saxena 
5775*2d1d418eSSumit Saxena 		DELAY(1000); /* delay in usec */
5776*2d1d418eSSumit Saxena 		host_diagnostic = mpi3mr_regread(sc, MPI3_SYSIF_HOST_DIAG_OFFSET);
5777*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
5778*2d1d418eSSumit Saxena 		    "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n",
5779*2d1d418eSSumit Saxena 		    unlock_retry_count, host_diagnostic);
5780*2d1d418eSSumit Saxena 	} while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE));
5781*2d1d418eSSumit Saxena 
5782*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_SCRATCHPAD0_OFFSET, reset_reason);
5783*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_HOST_DIAG_OFFSET, host_diagnostic | reset_type);
5784*2d1d418eSSumit Saxena 
5785*2d1d418eSSumit Saxena 	if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) {
5786*2d1d418eSSumit Saxena 		do {
5787*2d1d418eSSumit Saxena 			ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
5788*2d1d418eSSumit Saxena 			if (ioc_status &
5789*2d1d418eSSumit Saxena 			    MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
5790*2d1d418eSSumit Saxena 				ioc_config =
5791*2d1d418eSSumit Saxena 				    mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
5792*2d1d418eSSumit Saxena 				if (mpi3mr_soft_reset_success(ioc_status,
5793*2d1d418eSSumit Saxena 				    ioc_config)) {
5794*2d1d418eSSumit Saxena 					mpi3mr_clear_reset_history(sc);
5795*2d1d418eSSumit Saxena 					retval = 0;
5796*2d1d418eSSumit Saxena 					break;
5797*2d1d418eSSumit Saxena 				}
5798*2d1d418eSSumit Saxena 			}
5799*2d1d418eSSumit Saxena 			DELAY(100 * 1000);
5800*2d1d418eSSumit Saxena 		} while (--timeout);
5801*2d1d418eSSumit Saxena 	} else if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT) {
5802*2d1d418eSSumit Saxena 		do {
5803*2d1d418eSSumit Saxena 			ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
5804*2d1d418eSSumit Saxena 			if (mpi3mr_diagfault_success(sc, ioc_status)) {
5805*2d1d418eSSumit Saxena 				retval = 0;
5806*2d1d418eSSumit Saxena 				break;
5807*2d1d418eSSumit Saxena 			}
5808*2d1d418eSSumit Saxena 			DELAY(100 * 1000);
5809*2d1d418eSSumit Saxena 		} while (--timeout);
5810*2d1d418eSSumit Saxena 	}
5811*2d1d418eSSumit Saxena 
5812*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
5813*2d1d418eSSumit Saxena 		MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND);
5814*2d1d418eSSumit Saxena 
5815*2d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
5816*2d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
5817*2d1d418eSSumit Saxena 
5818*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
5819*2d1d418eSSumit Saxena 	    "IOC Status/Config after %s reset is (0x%x)/(0x%x)\n",
5820*2d1d418eSSumit Saxena 	    !retval ? "successful":"failed", ioc_status,
5821*2d1d418eSSumit Saxena 	    ioc_config);
5822*2d1d418eSSumit Saxena 
5823*2d1d418eSSumit Saxena 	if (retval)
5824*2d1d418eSSumit Saxena 		sc->unrecoverable = 1;
5825*2d1d418eSSumit Saxena 
5826*2d1d418eSSumit Saxena 	return retval;
5827*2d1d418eSSumit Saxena }
5828*2d1d418eSSumit Saxena 
5829*2d1d418eSSumit Saxena inline void mpi3mr_cleanup_event_taskq(struct mpi3mr_softc *sc)
5830*2d1d418eSSumit Saxena {
5831*2d1d418eSSumit Saxena 	mtx_lock(&sc->fwevt_lock);
5832*2d1d418eSSumit Saxena 	taskqueue_drain(sc->cam_sc->ev_tq, &sc->cam_sc->ev_task);
5833*2d1d418eSSumit Saxena 	taskqueue_block(sc->cam_sc->ev_tq);
5834*2d1d418eSSumit Saxena 	mtx_unlock(&sc->fwevt_lock);
5835*2d1d418eSSumit Saxena 	return;
5836*2d1d418eSSumit Saxena }
5837*2d1d418eSSumit Saxena 
5838*2d1d418eSSumit Saxena /**
5839*2d1d418eSSumit Saxena  * mpi3mr_soft_reset_handler - Reset the controller
5840*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
5841*2d1d418eSSumit Saxena  * @reset_reason: Reset reason code
5842*2d1d418eSSumit Saxena  * @snapdump: snapdump enable/disbale bit
5843*2d1d418eSSumit Saxena  *
5844*2d1d418eSSumit Saxena  * This is an handler for recovering controller by issuing soft
5845*2d1d418eSSumit Saxena  * reset or diag fault reset. This is a blocking function and
5846*2d1d418eSSumit Saxena  * when one reset is executed if any other resets they will be
5847*2d1d418eSSumit Saxena  * blocked. All IOCTLs/IO will be blocked during the reset. If
5848*2d1d418eSSumit Saxena  * controller reset is successful then the controller will be
5849*2d1d418eSSumit Saxena  * reinitalized, otherwise the controller will be marked as not
5850*2d1d418eSSumit Saxena  * recoverable
5851*2d1d418eSSumit Saxena  *
5852*2d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failure.
5853*2d1d418eSSumit Saxena  */
5854*2d1d418eSSumit Saxena int mpi3mr_soft_reset_handler(struct mpi3mr_softc *sc,
5855*2d1d418eSSumit Saxena 	U32 reset_reason, bool snapdump)
5856*2d1d418eSSumit Saxena {
5857*2d1d418eSSumit Saxena 	int retval = 0, i = 0;
5858*2d1d418eSSumit Saxena 	enum mpi3mr_iocstate ioc_state;
5859*2d1d418eSSumit Saxena 
5860*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "soft reset invoked: reason code: %s\n",
5861*2d1d418eSSumit Saxena 	    mpi3mr_reset_rc_name(reset_reason));
5862*2d1d418eSSumit Saxena 
5863*2d1d418eSSumit Saxena 	if ((reset_reason == MPI3MR_RESET_FROM_IOCTL) &&
5864*2d1d418eSSumit Saxena 	     (sc->reset.ioctl_reset_snapdump != true))
5865*2d1d418eSSumit Saxena 		snapdump = false;
5866*2d1d418eSSumit Saxena 
5867*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
5868*2d1d418eSSumit Saxena 	    "soft_reset_handler: wait if diag save is in progress\n");
5869*2d1d418eSSumit Saxena 	while (sc->diagsave_timeout)
5870*2d1d418eSSumit Saxena 		DELAY(1000 * 1000);
5871*2d1d418eSSumit Saxena 
5872*2d1d418eSSumit Saxena 	ioc_state = mpi3mr_get_iocstate(sc);
5873*2d1d418eSSumit Saxena 	if (ioc_state == MRIOC_STATE_UNRECOVERABLE) {
5874*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "controller is in unrecoverable state, exit\n");
5875*2d1d418eSSumit Saxena 		sc->reset.type = MPI3MR_NO_RESET;
5876*2d1d418eSSumit Saxena 		sc->reset.reason = MPI3MR_DEFAULT_RESET_REASON;
5877*2d1d418eSSumit Saxena 		sc->reset.status = -1;
5878*2d1d418eSSumit Saxena 		sc->reset.ioctl_reset_snapdump = false;
5879*2d1d418eSSumit Saxena 		return -1;
5880*2d1d418eSSumit Saxena 	}
5881*2d1d418eSSumit Saxena 
5882*2d1d418eSSumit Saxena 	if (sc->reset_in_progress) {
5883*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "reset is already in progress, exit\n");
5884*2d1d418eSSumit Saxena 		return -1;
5885*2d1d418eSSumit Saxena 	}
5886*2d1d418eSSumit Saxena 
5887*2d1d418eSSumit Saxena 	/* Pause IOs, drain and block the event taskqueue */
5888*2d1d418eSSumit Saxena 	xpt_freeze_simq(sc->cam_sc->sim, 1);
5889*2d1d418eSSumit Saxena 
5890*2d1d418eSSumit Saxena 	mpi3mr_cleanup_event_taskq(sc);
5891*2d1d418eSSumit Saxena 
5892*2d1d418eSSumit Saxena 	sc->reset_in_progress = 1;
5893*2d1d418eSSumit Saxena 	sc->block_ioctls = 1;
5894*2d1d418eSSumit Saxena 
5895*2d1d418eSSumit Saxena 	while (mpi3mr_atomic_read(&sc->pend_ioctls) && (i < PEND_IOCTLS_COMP_WAIT_TIME)) {
5896*2d1d418eSSumit Saxena 		ioc_state = mpi3mr_get_iocstate(sc);
5897*2d1d418eSSumit Saxena 		if (ioc_state == MRIOC_STATE_FAULT)
5898*2d1d418eSSumit Saxena 			break;
5899*2d1d418eSSumit Saxena 		i++;
5900*2d1d418eSSumit Saxena 		if (!(i % 5)) {
5901*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO,
5902*2d1d418eSSumit Saxena 			    "[%2ds]waiting for IOCTL to be finished from %s\n", i, __func__);
5903*2d1d418eSSumit Saxena 		}
5904*2d1d418eSSumit Saxena 		DELAY(1000 * 1000);
5905*2d1d418eSSumit Saxena 	}
5906*2d1d418eSSumit Saxena 
5907*2d1d418eSSumit Saxena 	if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
5908*2d1d418eSSumit Saxena 	    (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) &&
5909*2d1d418eSSumit Saxena 	    (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) {
5910*2d1d418eSSumit Saxena 
5911*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "Turn off events prior to reset\n");
5912*2d1d418eSSumit Saxena 
5913*2d1d418eSSumit Saxena 		for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
5914*2d1d418eSSumit Saxena 			sc->event_masks[i] = -1;
5915*2d1d418eSSumit Saxena 		mpi3mr_issue_event_notification(sc);
5916*2d1d418eSSumit Saxena 	}
5917*2d1d418eSSumit Saxena 
5918*2d1d418eSSumit Saxena 	mpi3mr_disable_interrupts(sc);
5919*2d1d418eSSumit Saxena 
5920*2d1d418eSSumit Saxena 	if (snapdump)
5921*2d1d418eSSumit Saxena 		mpi3mr_trigger_snapdump(sc, reset_reason);
5922*2d1d418eSSumit Saxena 
5923*2d1d418eSSumit Saxena 	retval = mpi3mr_issue_reset(sc,
5924*2d1d418eSSumit Saxena 	    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason);
5925*2d1d418eSSumit Saxena 	if (retval) {
5926*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to issue soft reset to the ioc\n");
5927*2d1d418eSSumit Saxena 		goto out;
5928*2d1d418eSSumit Saxena 	}
5929*2d1d418eSSumit Saxena 
5930*2d1d418eSSumit Saxena 	mpi3mr_flush_drv_cmds(sc);
5931*2d1d418eSSumit Saxena 	mpi3mr_flush_io(sc);
5932*2d1d418eSSumit Saxena 	mpi3mr_invalidate_devhandles(sc);
5933*2d1d418eSSumit Saxena 	mpi3mr_memset_buffers(sc);
5934*2d1d418eSSumit Saxena 
5935*2d1d418eSSumit Saxena 	if (sc->prepare_for_reset) {
5936*2d1d418eSSumit Saxena 		sc->prepare_for_reset = 0;
5937*2d1d418eSSumit Saxena 		sc->prepare_for_reset_timeout_counter = 0;
5938*2d1d418eSSumit Saxena 	}
5939*2d1d418eSSumit Saxena 
5940*2d1d418eSSumit Saxena 	retval = mpi3mr_initialize_ioc(sc, MPI3MR_INIT_TYPE_RESET);
5941*2d1d418eSSumit Saxena 	if (retval) {
5942*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "reinit after soft reset failed: reason %d\n",
5943*2d1d418eSSumit Saxena 		    reset_reason);
5944*2d1d418eSSumit Saxena 		goto out;
5945*2d1d418eSSumit Saxena 	}
5946*2d1d418eSSumit Saxena 
5947*2d1d418eSSumit Saxena 	DELAY((1000 * 1000) * 10);
5948*2d1d418eSSumit Saxena out:
5949*2d1d418eSSumit Saxena 	if (!retval) {
5950*2d1d418eSSumit Saxena 		sc->diagsave_timeout = 0;
5951*2d1d418eSSumit Saxena 		sc->reset_in_progress = 0;
5952*2d1d418eSSumit Saxena 		mpi3mr_rfresh_tgtdevs(sc);
5953*2d1d418eSSumit Saxena 		sc->ts_update_counter = 0;
5954*2d1d418eSSumit Saxena 		sc->block_ioctls = 0;
5955*2d1d418eSSumit Saxena 		sc->pel_abort_requested = 0;
5956*2d1d418eSSumit Saxena 		if (sc->pel_wait_pend) {
5957*2d1d418eSSumit Saxena 			sc->pel_cmds.retry_count = 0;
5958*2d1d418eSSumit Saxena 			mpi3mr_issue_pel_wait(sc, &sc->pel_cmds);
5959*2d1d418eSSumit Saxena 			mpi3mr_app_send_aen(sc);
5960*2d1d418eSSumit Saxena 		}
5961*2d1d418eSSumit Saxena 	} else {
5962*2d1d418eSSumit Saxena 		mpi3mr_issue_reset(sc,
5963*2d1d418eSSumit Saxena 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
5964*2d1d418eSSumit Saxena 		sc->unrecoverable = 1;
5965*2d1d418eSSumit Saxena 		sc->reset_in_progress = 0;
5966*2d1d418eSSumit Saxena 	}
5967*2d1d418eSSumit Saxena 
5968*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "Soft Reset: %s\n", ((retval == 0) ? "SUCCESS" : "FAILED"));
5969*2d1d418eSSumit Saxena 
5970*2d1d418eSSumit Saxena 	taskqueue_unblock(sc->cam_sc->ev_tq);
5971*2d1d418eSSumit Saxena 	xpt_release_simq(sc->cam_sc->sim, 1);
5972*2d1d418eSSumit Saxena 
5973*2d1d418eSSumit Saxena 	sc->reset.type = MPI3MR_NO_RESET;
5974*2d1d418eSSumit Saxena 	sc->reset.reason = MPI3MR_DEFAULT_RESET_REASON;
5975*2d1d418eSSumit Saxena 	sc->reset.status = retval;
5976*2d1d418eSSumit Saxena 	sc->reset.ioctl_reset_snapdump = false;
5977*2d1d418eSSumit Saxena 
5978*2d1d418eSSumit Saxena 	return retval;
5979*2d1d418eSSumit Saxena }
5980*2d1d418eSSumit Saxena 
5981*2d1d418eSSumit Saxena /**
5982*2d1d418eSSumit Saxena  * mpi3mr_issue_ioc_shutdown - shutdown controller
5983*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
5984*2d1d418eSSumit Saxena  *
5985*2d1d418eSSumit Saxena  * Send shutodwn notification to the controller and wait for the
5986*2d1d418eSSumit Saxena  * shutdown_timeout for it to be completed.
5987*2d1d418eSSumit Saxena  *
5988*2d1d418eSSumit Saxena  * Return: Nothing.
5989*2d1d418eSSumit Saxena  */
5990*2d1d418eSSumit Saxena static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_softc *sc)
5991*2d1d418eSSumit Saxena {
5992*2d1d418eSSumit Saxena 	U32 ioc_config, ioc_status;
5993*2d1d418eSSumit Saxena 	U8 retval = 1, retry = 0;
5994*2d1d418eSSumit Saxena 	U32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10;
5995*2d1d418eSSumit Saxena 
5996*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "sending shutdown notification\n");
5997*2d1d418eSSumit Saxena 	if (sc->unrecoverable) {
5998*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
5999*2d1d418eSSumit Saxena 		    "controller is unrecoverable, shutdown not issued\n");
6000*2d1d418eSSumit Saxena 		return;
6001*2d1d418eSSumit Saxena 	}
6002*2d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
6003*2d1d418eSSumit Saxena 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
6004*2d1d418eSSumit Saxena 	    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) {
6005*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "shutdown already in progress\n");
6006*2d1d418eSSumit Saxena 		return;
6007*2d1d418eSSumit Saxena 	}
6008*2d1d418eSSumit Saxena 
6009*2d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
6010*2d1d418eSSumit Saxena 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
6011*2d1d418eSSumit Saxena 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
6012*2d1d418eSSumit Saxena 
6013*2d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
6014*2d1d418eSSumit Saxena 
6015*2d1d418eSSumit Saxena 	if (sc->facts.shutdown_timeout)
6016*2d1d418eSSumit Saxena 		timeout = sc->facts.shutdown_timeout * 10;
6017*2d1d418eSSumit Saxena 
6018*2d1d418eSSumit Saxena 	do {
6019*2d1d418eSSumit Saxena 		ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
6020*2d1d418eSSumit Saxena 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
6021*2d1d418eSSumit Saxena 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) {
6022*2d1d418eSSumit Saxena 			retval = 0;
6023*2d1d418eSSumit Saxena 			break;
6024*2d1d418eSSumit Saxena 		}
6025*2d1d418eSSumit Saxena 
6026*2d1d418eSSumit Saxena 		if (sc->unrecoverable)
6027*2d1d418eSSumit Saxena 			break;
6028*2d1d418eSSumit Saxena 
6029*2d1d418eSSumit Saxena 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
6030*2d1d418eSSumit Saxena 			mpi3mr_print_fault_info(sc);
6031*2d1d418eSSumit Saxena 
6032*2d1d418eSSumit Saxena 			if (retry >= MPI3MR_MAX_SHUTDOWN_RETRY_COUNT)
6033*2d1d418eSSumit Saxena 				break;
6034*2d1d418eSSumit Saxena 
6035*2d1d418eSSumit Saxena 			if (mpi3mr_issue_reset(sc,
6036*2d1d418eSSumit Saxena 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
6037*2d1d418eSSumit Saxena 			    MPI3MR_RESET_FROM_CTLR_CLEANUP))
6038*2d1d418eSSumit Saxena 				break;
6039*2d1d418eSSumit Saxena 
6040*2d1d418eSSumit Saxena 			ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
6041*2d1d418eSSumit Saxena 			ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
6042*2d1d418eSSumit Saxena 			ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
6043*2d1d418eSSumit Saxena 
6044*2d1d418eSSumit Saxena 			mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
6045*2d1d418eSSumit Saxena 
6046*2d1d418eSSumit Saxena 			if (sc->facts.shutdown_timeout)
6047*2d1d418eSSumit Saxena 				timeout = sc->facts.shutdown_timeout * 10;
6048*2d1d418eSSumit Saxena 
6049*2d1d418eSSumit Saxena 			retry++;
6050*2d1d418eSSumit Saxena 		}
6051*2d1d418eSSumit Saxena 
6052*2d1d418eSSumit Saxena                 DELAY(100 * 1000);
6053*2d1d418eSSumit Saxena 
6054*2d1d418eSSumit Saxena 	} while (--timeout);
6055*2d1d418eSSumit Saxena 
6056*2d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
6057*2d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
6058*2d1d418eSSumit Saxena 
6059*2d1d418eSSumit Saxena 	if (retval) {
6060*2d1d418eSSumit Saxena 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
6061*2d1d418eSSumit Saxena 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
6062*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
6063*2d1d418eSSumit Saxena 			    "shutdown still in progress after timeout\n");
6064*2d1d418eSSumit Saxena 	}
6065*2d1d418eSSumit Saxena 
6066*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
6067*2d1d418eSSumit Saxena 	    "ioc_status/ioc_config after %s shutdown is (0x%x)/(0x%x)\n",
6068*2d1d418eSSumit Saxena 	    (!retval)?"successful":"failed", ioc_status,
6069*2d1d418eSSumit Saxena 	    ioc_config);
6070*2d1d418eSSumit Saxena }
6071*2d1d418eSSumit Saxena 
6072*2d1d418eSSumit Saxena /**
6073*2d1d418eSSumit Saxena  * mpi3mr_cleanup_ioc - Cleanup controller
6074*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
6075*2d1d418eSSumit Saxena 
6076*2d1d418eSSumit Saxena  * controller cleanup handler, Message unit reset or soft reset
6077*2d1d418eSSumit Saxena  * and shutdown notification is issued to the controller.
6078*2d1d418eSSumit Saxena  *
6079*2d1d418eSSumit Saxena  * Return: Nothing.
6080*2d1d418eSSumit Saxena  */
6081*2d1d418eSSumit Saxena void mpi3mr_cleanup_ioc(struct mpi3mr_softc *sc)
6082*2d1d418eSSumit Saxena {
6083*2d1d418eSSumit Saxena 	enum mpi3mr_iocstate ioc_state;
6084*2d1d418eSSumit Saxena 
6085*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "cleaning up the controller\n");
6086*2d1d418eSSumit Saxena 	mpi3mr_disable_interrupts(sc);
6087*2d1d418eSSumit Saxena 
6088*2d1d418eSSumit Saxena 	ioc_state = mpi3mr_get_iocstate(sc);
6089*2d1d418eSSumit Saxena 
6090*2d1d418eSSumit Saxena 	if ((!sc->unrecoverable) && (!sc->reset_in_progress) &&
6091*2d1d418eSSumit Saxena 	    (ioc_state == MRIOC_STATE_READY)) {
6092*2d1d418eSSumit Saxena 		if (mpi3mr_mur_ioc(sc,
6093*2d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_CTLR_CLEANUP))
6094*2d1d418eSSumit Saxena 			mpi3mr_issue_reset(sc,
6095*2d1d418eSSumit Saxena 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
6096*2d1d418eSSumit Saxena 			    MPI3MR_RESET_FROM_MUR_FAILURE);
6097*2d1d418eSSumit Saxena 		mpi3mr_issue_ioc_shutdown(sc);
6098*2d1d418eSSumit Saxena 	}
6099*2d1d418eSSumit Saxena 
6100*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "controller cleanup completed\n");
6101*2d1d418eSSumit Saxena }
6102