xref: /freebsd/sys/dev/mpi3mr/mpi3mr.c (revision 7c4913093a759adf2e4c7d65535aee04aadee4df)
12d1d418eSSumit Saxena /*
22d1d418eSSumit Saxena  * SPDX-License-Identifier: BSD-2-Clause
32d1d418eSSumit Saxena  *
42d1d418eSSumit Saxena  * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved.
52d1d418eSSumit Saxena  * Support: <fbsd-storage-driver.pdl@broadcom.com>
62d1d418eSSumit Saxena  *
72d1d418eSSumit Saxena  * Authors: Sumit Saxena <sumit.saxena@broadcom.com>
82d1d418eSSumit Saxena  *	    Chandrakanth Patil <chandrakanth.patil@broadcom.com>
92d1d418eSSumit Saxena  *
102d1d418eSSumit Saxena  * Redistribution and use in source and binary forms, with or without
112d1d418eSSumit Saxena  * modification, are permitted provided that the following conditions are
122d1d418eSSumit Saxena  * met:
132d1d418eSSumit Saxena  *
142d1d418eSSumit Saxena  * 1. Redistributions of source code must retain the above copyright notice,
152d1d418eSSumit Saxena  *    this list of conditions and the following disclaimer.
162d1d418eSSumit Saxena  * 2. Redistributions in binary form must reproduce the above copyright notice,
172d1d418eSSumit Saxena  *    this list of conditions and the following disclaimer in the documentation and/or other
182d1d418eSSumit Saxena  *    materials provided with the distribution.
192d1d418eSSumit Saxena  * 3. Neither the name of the Broadcom Inc. nor the names of its contributors
202d1d418eSSumit Saxena  *    may be used to endorse or promote products derived from this software without
212d1d418eSSumit Saxena  *    specific prior written permission.
222d1d418eSSumit Saxena  *
232d1d418eSSumit Saxena  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
242d1d418eSSumit Saxena  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
252d1d418eSSumit Saxena  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
262d1d418eSSumit Saxena  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
272d1d418eSSumit Saxena  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
282d1d418eSSumit Saxena  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
292d1d418eSSumit Saxena  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
302d1d418eSSumit Saxena  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
312d1d418eSSumit Saxena  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
322d1d418eSSumit Saxena  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
332d1d418eSSumit Saxena  * POSSIBILITY OF SUCH DAMAGE.
342d1d418eSSumit Saxena  *
352d1d418eSSumit Saxena  * The views and conclusions contained in the software and documentation are
362d1d418eSSumit Saxena  * those of the authors and should not be interpreted as representing
372d1d418eSSumit Saxena  * official policies,either expressed or implied, of the FreeBSD Project.
382d1d418eSSumit Saxena  *
392d1d418eSSumit Saxena  * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131
402d1d418eSSumit Saxena  *
412d1d418eSSumit Saxena  * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD
422d1d418eSSumit Saxena  */
432d1d418eSSumit Saxena 
442d1d418eSSumit Saxena #include <sys/types.h>
452d1d418eSSumit Saxena #include <sys/param.h>
462d1d418eSSumit Saxena #include <sys/systm.h>
472d1d418eSSumit Saxena #include <sys/kernel.h>
482d1d418eSSumit Saxena #include <sys/module.h>
492d1d418eSSumit Saxena #include <sys/bus.h>
502d1d418eSSumit Saxena #include <sys/conf.h>
512d1d418eSSumit Saxena #include <sys/malloc.h>
522d1d418eSSumit Saxena #include <sys/sysctl.h>
532d1d418eSSumit Saxena #include <sys/uio.h>
542d1d418eSSumit Saxena 
552d1d418eSSumit Saxena #include <machine/bus.h>
562d1d418eSSumit Saxena #include <machine/resource.h>
572d1d418eSSumit Saxena #include <sys/rman.h>
582d1d418eSSumit Saxena 
592d1d418eSSumit Saxena #include <dev/pci/pcireg.h>
602d1d418eSSumit Saxena #include <dev/pci/pcivar.h>
612d1d418eSSumit Saxena #include <dev/pci/pci_private.h>
622d1d418eSSumit Saxena 
632d1d418eSSumit Saxena #include <cam/cam.h>
642d1d418eSSumit Saxena #include <cam/cam_ccb.h>
652d1d418eSSumit Saxena #include <cam/cam_debug.h>
662d1d418eSSumit Saxena #include <cam/cam_sim.h>
672d1d418eSSumit Saxena #include <cam/cam_xpt_sim.h>
682d1d418eSSumit Saxena #include <cam/cam_xpt_periph.h>
692d1d418eSSumit Saxena #include <cam/cam_periph.h>
702d1d418eSSumit Saxena #include <cam/scsi/scsi_all.h>
712d1d418eSSumit Saxena #include <cam/scsi/scsi_message.h>
722d1d418eSSumit Saxena #include <cam/scsi/smp_all.h>
732d1d418eSSumit Saxena #include <sys/queue.h>
742d1d418eSSumit Saxena #include <sys/kthread.h>
752d1d418eSSumit Saxena #include "mpi3mr.h"
762d1d418eSSumit Saxena #include "mpi3mr_cam.h"
772d1d418eSSumit Saxena #include "mpi3mr_app.h"
782d1d418eSSumit Saxena 
792d1d418eSSumit Saxena static void mpi3mr_repost_reply_buf(struct mpi3mr_softc *sc,
802d1d418eSSumit Saxena 	U64 reply_dma);
812d1d418eSSumit Saxena static int mpi3mr_complete_admin_cmd(struct mpi3mr_softc *sc);
822d1d418eSSumit Saxena static void mpi3mr_port_enable_complete(struct mpi3mr_softc *sc,
832d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drvrcmd);
842d1d418eSSumit Saxena static void mpi3mr_flush_io(struct mpi3mr_softc *sc);
852d1d418eSSumit Saxena static int mpi3mr_issue_reset(struct mpi3mr_softc *sc, U16 reset_type,
862d1d418eSSumit Saxena 	U32 reset_reason);
872d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_softc *sc, U16 handle,
882d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdparam, U8 iou_rc);
892d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_softc *sc,
902d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd);
912d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_complete_tm(struct mpi3mr_softc *sc,
922d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd);
932d1d418eSSumit Saxena static void mpi3mr_send_evt_ack(struct mpi3mr_softc *sc, U8 event,
942d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdparam, U32 event_ctx);
952d1d418eSSumit Saxena static void mpi3mr_print_fault_info(struct mpi3mr_softc *sc);
962d1d418eSSumit Saxena static inline void mpi3mr_set_diagsave(struct mpi3mr_softc *sc);
972d1d418eSSumit Saxena static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code);
982d1d418eSSumit Saxena 
992d1d418eSSumit Saxena void
1002d1d418eSSumit Saxena mpi3mr_hexdump(void *buf, int sz, int format)
1012d1d418eSSumit Saxena {
1022d1d418eSSumit Saxena         int i;
1032d1d418eSSumit Saxena         U32 *buf_loc = (U32 *)buf;
1042d1d418eSSumit Saxena 
1052d1d418eSSumit Saxena         for (i = 0; i < (sz / sizeof(U32)); i++) {
1062d1d418eSSumit Saxena                 if ((i % format) == 0) {
1072d1d418eSSumit Saxena                         if (i != 0)
1082d1d418eSSumit Saxena                                 printf("\n");
1092d1d418eSSumit Saxena                         printf("%08x: ", (i * 4));
1102d1d418eSSumit Saxena                 }
1112d1d418eSSumit Saxena                 printf("%08x ", buf_loc[i]);
1122d1d418eSSumit Saxena         }
1132d1d418eSSumit Saxena         printf("\n");
1142d1d418eSSumit Saxena }
1152d1d418eSSumit Saxena 
1162d1d418eSSumit Saxena void
1172d1d418eSSumit Saxena init_completion(struct completion *completion)
1182d1d418eSSumit Saxena {
1192d1d418eSSumit Saxena 	completion->done = 0;
1202d1d418eSSumit Saxena }
1212d1d418eSSumit Saxena 
1222d1d418eSSumit Saxena void
1232d1d418eSSumit Saxena complete(struct completion *completion)
1242d1d418eSSumit Saxena {
1252d1d418eSSumit Saxena 	completion->done = 1;
1262d1d418eSSumit Saxena 	wakeup(complete);
1272d1d418eSSumit Saxena }
1282d1d418eSSumit Saxena 
1292d1d418eSSumit Saxena void wait_for_completion_timeout(struct completion *completion,
1302d1d418eSSumit Saxena 	    U32 timeout)
1312d1d418eSSumit Saxena {
1322d1d418eSSumit Saxena 	U32 count = timeout * 1000;
1332d1d418eSSumit Saxena 
1342d1d418eSSumit Saxena 	while ((completion->done == 0) && count) {
1352d1d418eSSumit Saxena                 DELAY(1000);
1362d1d418eSSumit Saxena 		count--;
1372d1d418eSSumit Saxena 	}
1382d1d418eSSumit Saxena 
1392d1d418eSSumit Saxena 	if (completion->done == 0) {
1402d1d418eSSumit Saxena 		printf("%s: Command is timedout\n", __func__);
1412d1d418eSSumit Saxena 		completion->done = 1;
1422d1d418eSSumit Saxena 	}
1432d1d418eSSumit Saxena }
1442d1d418eSSumit Saxena void wait_for_completion_timeout_tm(struct completion *completion,
1452d1d418eSSumit Saxena 	    U32 timeout, struct mpi3mr_softc *sc)
1462d1d418eSSumit Saxena {
1472d1d418eSSumit Saxena 	U32 count = timeout * 1000;
1482d1d418eSSumit Saxena 
1492d1d418eSSumit Saxena 	while ((completion->done == 0) && count) {
1502d1d418eSSumit Saxena 		msleep(&sc->tm_chan, &sc->mpi3mr_mtx, PRIBIO,
1512d1d418eSSumit Saxena 		       "TM command", 1 * hz);
1522d1d418eSSumit Saxena 		count--;
1532d1d418eSSumit Saxena 	}
1542d1d418eSSumit Saxena 
1552d1d418eSSumit Saxena 	if (completion->done == 0) {
1562d1d418eSSumit Saxena 		printf("%s: Command is timedout\n", __func__);
1572d1d418eSSumit Saxena 		completion->done = 1;
1582d1d418eSSumit Saxena 	}
1592d1d418eSSumit Saxena }
1602d1d418eSSumit Saxena 
1612d1d418eSSumit Saxena 
1622d1d418eSSumit Saxena void
1632d1d418eSSumit Saxena poll_for_command_completion(struct mpi3mr_softc *sc,
1642d1d418eSSumit Saxena        struct mpi3mr_drvr_cmd *cmd, U16 wait)
1652d1d418eSSumit Saxena {
1662d1d418eSSumit Saxena 	int wait_time = wait * 1000;
1672d1d418eSSumit Saxena        while (wait_time) {
1682d1d418eSSumit Saxena                mpi3mr_complete_admin_cmd(sc);
1692d1d418eSSumit Saxena                if (cmd->state & MPI3MR_CMD_COMPLETE)
1702d1d418eSSumit Saxena                        break;
1712d1d418eSSumit Saxena 	       DELAY(1000);
1722d1d418eSSumit Saxena                wait_time--;
1732d1d418eSSumit Saxena        }
1742d1d418eSSumit Saxena }
1752d1d418eSSumit Saxena 
1762d1d418eSSumit Saxena /**
1772d1d418eSSumit Saxena  * mpi3mr_trigger_snapdump - triggers firmware snapdump
1782d1d418eSSumit Saxena  * @sc: Adapter instance reference
1792d1d418eSSumit Saxena  * @reason_code: reason code for the fault.
1802d1d418eSSumit Saxena  *
1812d1d418eSSumit Saxena  * This routine will trigger the snapdump and wait for it to
1822d1d418eSSumit Saxena  * complete or timeout before it returns.
1832d1d418eSSumit Saxena  * This will be called during initilaization time faults/resets/timeouts
1842d1d418eSSumit Saxena  * before soft reset invocation.
1852d1d418eSSumit Saxena  *
1862d1d418eSSumit Saxena  * Return:  None.
1872d1d418eSSumit Saxena  */
1882d1d418eSSumit Saxena static void
1892d1d418eSSumit Saxena mpi3mr_trigger_snapdump(struct mpi3mr_softc *sc, U32 reason_code)
1902d1d418eSSumit Saxena {
1912d1d418eSSumit Saxena 	U32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
1922d1d418eSSumit Saxena 
1932d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "snapdump triggered: reason code: %s\n",
1942d1d418eSSumit Saxena 	    mpi3mr_reset_rc_name(reason_code));
1952d1d418eSSumit Saxena 
1962d1d418eSSumit Saxena 	mpi3mr_set_diagsave(sc);
1972d1d418eSSumit Saxena 	mpi3mr_issue_reset(sc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
1982d1d418eSSumit Saxena 			   reason_code);
1992d1d418eSSumit Saxena 
2002d1d418eSSumit Saxena 	do {
2012d1d418eSSumit Saxena 		host_diagnostic = mpi3mr_regread(sc, MPI3_SYSIF_HOST_DIAG_OFFSET);
2022d1d418eSSumit Saxena 		if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
2032d1d418eSSumit Saxena 			break;
2042d1d418eSSumit Saxena                 DELAY(100 * 1000);
2052d1d418eSSumit Saxena 	} while (--timeout);
2062d1d418eSSumit Saxena 
2072d1d418eSSumit Saxena 	return;
2082d1d418eSSumit Saxena }
2092d1d418eSSumit Saxena 
2102d1d418eSSumit Saxena /**
2112d1d418eSSumit Saxena  * mpi3mr_check_rh_fault_ioc - check reset history and fault
2122d1d418eSSumit Saxena  * controller
2132d1d418eSSumit Saxena  * @sc: Adapter instance reference
2142d1d418eSSumit Saxena  * @reason_code, reason code for the fault.
2152d1d418eSSumit Saxena  *
2162d1d418eSSumit Saxena  * This routine will fault the controller with
2172d1d418eSSumit Saxena  * the given reason code if it is not already in the fault or
2182d1d418eSSumit Saxena  * not asynchronosuly reset. This will be used to handle
2192d1d418eSSumit Saxena  * initilaization time faults/resets/timeout as in those cases
2202d1d418eSSumit Saxena  * immediate soft reset invocation is not required.
2212d1d418eSSumit Saxena  *
2222d1d418eSSumit Saxena  * Return:  None.
2232d1d418eSSumit Saxena  */
2242d1d418eSSumit Saxena static void mpi3mr_check_rh_fault_ioc(struct mpi3mr_softc *sc, U32 reason_code)
2252d1d418eSSumit Saxena {
2262d1d418eSSumit Saxena 	U32 ioc_status;
2272d1d418eSSumit Saxena 
2282d1d418eSSumit Saxena 	if (sc->unrecoverable) {
2292d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "controller is unrecoverable\n");
2302d1d418eSSumit Saxena 		return;
2312d1d418eSSumit Saxena 	}
2322d1d418eSSumit Saxena 
2332d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
2342d1d418eSSumit Saxena 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
2352d1d418eSSumit Saxena 	    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
2362d1d418eSSumit Saxena 		mpi3mr_print_fault_info(sc);
2372d1d418eSSumit Saxena 		return;
2382d1d418eSSumit Saxena 	}
2392d1d418eSSumit Saxena 
2402d1d418eSSumit Saxena 	mpi3mr_trigger_snapdump(sc, reason_code);
2412d1d418eSSumit Saxena 
2422d1d418eSSumit Saxena 	return;
2432d1d418eSSumit Saxena }
2442d1d418eSSumit Saxena 
2452d1d418eSSumit Saxena static void * mpi3mr_get_reply_virt_addr(struct mpi3mr_softc *sc,
2462d1d418eSSumit Saxena     bus_addr_t phys_addr)
2472d1d418eSSumit Saxena {
2482d1d418eSSumit Saxena 	if (!phys_addr)
2492d1d418eSSumit Saxena 		return NULL;
2502d1d418eSSumit Saxena 	if ((phys_addr < sc->reply_buf_dma_min_address) ||
2512d1d418eSSumit Saxena 	    (phys_addr > sc->reply_buf_dma_max_address))
2522d1d418eSSumit Saxena 		return NULL;
2532d1d418eSSumit Saxena 
2542d1d418eSSumit Saxena 	return sc->reply_buf + (phys_addr - sc->reply_buf_phys);
2552d1d418eSSumit Saxena }
2562d1d418eSSumit Saxena 
2572d1d418eSSumit Saxena static void * mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_softc *sc,
2582d1d418eSSumit Saxena     bus_addr_t phys_addr)
2592d1d418eSSumit Saxena {
2602d1d418eSSumit Saxena 	if (!phys_addr)
2612d1d418eSSumit Saxena 		return NULL;
2622d1d418eSSumit Saxena 	return sc->sense_buf + (phys_addr - sc->sense_buf_phys);
2632d1d418eSSumit Saxena }
2642d1d418eSSumit Saxena 
2652d1d418eSSumit Saxena static void mpi3mr_repost_reply_buf(struct mpi3mr_softc *sc,
2662d1d418eSSumit Saxena     U64 reply_dma)
2672d1d418eSSumit Saxena {
2682d1d418eSSumit Saxena 	U32 old_idx = 0;
2692d1d418eSSumit Saxena 
2702d1d418eSSumit Saxena 	mtx_lock_spin(&sc->reply_free_q_lock);
2712d1d418eSSumit Saxena 	old_idx  =  sc->reply_free_q_host_index;
2722d1d418eSSumit Saxena 	sc->reply_free_q_host_index = ((sc->reply_free_q_host_index ==
2732d1d418eSSumit Saxena 	    (sc->reply_free_q_sz - 1)) ? 0 :
2742d1d418eSSumit Saxena 	    (sc->reply_free_q_host_index + 1));
2752d1d418eSSumit Saxena 	sc->reply_free_q[old_idx] = reply_dma;
2762d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_REPLY_FREE_HOST_INDEX_OFFSET,
2772d1d418eSSumit Saxena 		sc->reply_free_q_host_index);
2782d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->reply_free_q_lock);
2792d1d418eSSumit Saxena }
2802d1d418eSSumit Saxena 
2812d1d418eSSumit Saxena static void mpi3mr_repost_sense_buf(struct mpi3mr_softc *sc,
2822d1d418eSSumit Saxena     U64 sense_buf_phys)
2832d1d418eSSumit Saxena {
2842d1d418eSSumit Saxena 	U32 old_idx = 0;
2852d1d418eSSumit Saxena 
2862d1d418eSSumit Saxena 	mtx_lock_spin(&sc->sense_buf_q_lock);
2872d1d418eSSumit Saxena 	old_idx  =  sc->sense_buf_q_host_index;
2882d1d418eSSumit Saxena 	sc->sense_buf_q_host_index = ((sc->sense_buf_q_host_index ==
2892d1d418eSSumit Saxena 	    (sc->sense_buf_q_sz - 1)) ? 0 :
2902d1d418eSSumit Saxena 	    (sc->sense_buf_q_host_index + 1));
2912d1d418eSSumit Saxena 	sc->sense_buf_q[old_idx] = sense_buf_phys;
2922d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_SENSE_BUF_FREE_HOST_INDEX_OFFSET,
2932d1d418eSSumit Saxena 		sc->sense_buf_q_host_index);
2942d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->sense_buf_q_lock);
2952d1d418eSSumit Saxena 
2962d1d418eSSumit Saxena }
2972d1d418eSSumit Saxena 
2982d1d418eSSumit Saxena void mpi3mr_set_io_divert_for_all_vd_in_tg(struct mpi3mr_softc *sc,
2992d1d418eSSumit Saxena 	struct mpi3mr_throttle_group_info *tg, U8 divert_value)
3002d1d418eSSumit Saxena {
3012d1d418eSSumit Saxena 	struct mpi3mr_target *target;
3022d1d418eSSumit Saxena 
3032d1d418eSSumit Saxena 	mtx_lock_spin(&sc->target_lock);
3042d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) {
3052d1d418eSSumit Saxena 		if (target->throttle_group == tg)
3062d1d418eSSumit Saxena 			target->io_divert = divert_value;
3072d1d418eSSumit Saxena 	}
3082d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->target_lock);
3092d1d418eSSumit Saxena }
3102d1d418eSSumit Saxena 
3112d1d418eSSumit Saxena /**
3122d1d418eSSumit Saxena  * mpi3mr_submit_admin_cmd - Submit request to admin queue
3132d1d418eSSumit Saxena  * @mrioc: Adapter reference
3142d1d418eSSumit Saxena  * @admin_req: MPI3 request
3152d1d418eSSumit Saxena  * @admin_req_sz: Request size
3162d1d418eSSumit Saxena  *
3172d1d418eSSumit Saxena  * Post the MPI3 request into admin request queue and
3182d1d418eSSumit Saxena  * inform the controller, if the queue is full return
3192d1d418eSSumit Saxena  * appropriate error.
3202d1d418eSSumit Saxena  *
3212d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failure.
3222d1d418eSSumit Saxena  */
3232d1d418eSSumit Saxena int mpi3mr_submit_admin_cmd(struct mpi3mr_softc *sc, void *admin_req,
3242d1d418eSSumit Saxena     U16 admin_req_sz)
3252d1d418eSSumit Saxena {
3262d1d418eSSumit Saxena 	U16 areq_pi = 0, areq_ci = 0, max_entries = 0;
3272d1d418eSSumit Saxena 	int retval = 0;
3282d1d418eSSumit Saxena 	U8 *areq_entry;
3292d1d418eSSumit Saxena 
3302d1d418eSSumit Saxena 	mtx_lock_spin(&sc->admin_req_lock);
3312d1d418eSSumit Saxena 	areq_pi = sc->admin_req_pi;
3322d1d418eSSumit Saxena 	areq_ci = sc->admin_req_ci;
3332d1d418eSSumit Saxena 	max_entries = sc->num_admin_reqs;
3342d1d418eSSumit Saxena 
3352d1d418eSSumit Saxena 	if (sc->unrecoverable)
3362d1d418eSSumit Saxena 		return -EFAULT;
3372d1d418eSSumit Saxena 
3382d1d418eSSumit Saxena 	if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) &&
3392d1d418eSSumit Saxena 					   (areq_pi == (max_entries - 1)))) {
3402d1d418eSSumit Saxena 		printf(IOCNAME "AdminReqQ full condition detected\n",
3412d1d418eSSumit Saxena 		    sc->name);
3422d1d418eSSumit Saxena 		retval = -EAGAIN;
3432d1d418eSSumit Saxena 		goto out;
3442d1d418eSSumit Saxena 	}
3452d1d418eSSumit Saxena 	areq_entry = (U8 *)sc->admin_req + (areq_pi *
3462d1d418eSSumit Saxena 						     MPI3MR_AREQ_FRAME_SZ);
3472d1d418eSSumit Saxena 	memset(areq_entry, 0, MPI3MR_AREQ_FRAME_SZ);
3482d1d418eSSumit Saxena 	memcpy(areq_entry, (U8 *)admin_req, admin_req_sz);
3492d1d418eSSumit Saxena 
3502d1d418eSSumit Saxena 	if (++areq_pi == max_entries)
3512d1d418eSSumit Saxena 		areq_pi = 0;
3522d1d418eSSumit Saxena 	sc->admin_req_pi = areq_pi;
3532d1d418eSSumit Saxena 
3542d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REQ_Q_PI_OFFSET, sc->admin_req_pi);
3552d1d418eSSumit Saxena 
3562d1d418eSSumit Saxena out:
3572d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->admin_req_lock);
3582d1d418eSSumit Saxena 	return retval;
3592d1d418eSSumit Saxena }
3602d1d418eSSumit Saxena 
3612d1d418eSSumit Saxena /**
3622d1d418eSSumit Saxena  * mpi3mr_check_req_qfull - Check request queue is full or not
3632d1d418eSSumit Saxena  * @op_req_q: Operational reply queue info
3642d1d418eSSumit Saxena  *
3652d1d418eSSumit Saxena  * Return: true when queue full, false otherwise.
3662d1d418eSSumit Saxena  */
3672d1d418eSSumit Saxena static inline bool
3682d1d418eSSumit Saxena mpi3mr_check_req_qfull(struct mpi3mr_op_req_queue *op_req_q)
3692d1d418eSSumit Saxena {
3702d1d418eSSumit Saxena 	U16 pi, ci, max_entries;
3712d1d418eSSumit Saxena 	bool is_qfull = false;
3722d1d418eSSumit Saxena 
3732d1d418eSSumit Saxena 	pi = op_req_q->pi;
3742d1d418eSSumit Saxena 	ci = op_req_q->ci;
3752d1d418eSSumit Saxena 	max_entries = op_req_q->num_reqs;
3762d1d418eSSumit Saxena 
3772d1d418eSSumit Saxena 	if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1))))
3782d1d418eSSumit Saxena 		is_qfull = true;
3792d1d418eSSumit Saxena 
3802d1d418eSSumit Saxena 	return is_qfull;
3812d1d418eSSumit Saxena }
3822d1d418eSSumit Saxena 
3832d1d418eSSumit Saxena /**
3842d1d418eSSumit Saxena  * mpi3mr_submit_io - Post IO command to firmware
3852d1d418eSSumit Saxena  * @sc:		      Adapter instance reference
3862d1d418eSSumit Saxena  * @op_req_q:	      Operational Request queue reference
3872d1d418eSSumit Saxena  * @req:	      MPT request data
3882d1d418eSSumit Saxena  *
3892d1d418eSSumit Saxena  * This function submits IO command to firmware.
3902d1d418eSSumit Saxena  *
3912d1d418eSSumit Saxena  * Return: Nothing
3922d1d418eSSumit Saxena  */
3932d1d418eSSumit Saxena int mpi3mr_submit_io(struct mpi3mr_softc *sc,
3942d1d418eSSumit Saxena     struct mpi3mr_op_req_queue *op_req_q, U8 *req)
3952d1d418eSSumit Saxena {
3962d1d418eSSumit Saxena 	U16 pi, max_entries;
3972d1d418eSSumit Saxena 	int retval = 0;
3982d1d418eSSumit Saxena 	U8 *req_entry;
3992d1d418eSSumit Saxena 	U16 req_sz = sc->facts.op_req_sz;
4002d1d418eSSumit Saxena 	struct mpi3mr_irq_context *irq_ctx;
4012d1d418eSSumit Saxena 
4022d1d418eSSumit Saxena 	mtx_lock_spin(&op_req_q->q_lock);
4032d1d418eSSumit Saxena 
4042d1d418eSSumit Saxena 	pi = op_req_q->pi;
4052d1d418eSSumit Saxena 	max_entries = op_req_q->num_reqs;
4062d1d418eSSumit Saxena 	if (mpi3mr_check_req_qfull(op_req_q)) {
4072d1d418eSSumit Saxena 		irq_ctx = &sc->irq_ctx[op_req_q->reply_qid - 1];
4082d1d418eSSumit Saxena 		mpi3mr_complete_io_cmd(sc, irq_ctx);
4092d1d418eSSumit Saxena 
4102d1d418eSSumit Saxena 		if (mpi3mr_check_req_qfull(op_req_q)) {
4112d1d418eSSumit Saxena 			printf(IOCNAME "OpReqQ full condition detected\n",
4122d1d418eSSumit Saxena 				sc->name);
4132d1d418eSSumit Saxena 			retval = -EBUSY;
4142d1d418eSSumit Saxena 			goto out;
4152d1d418eSSumit Saxena 		}
4162d1d418eSSumit Saxena 	}
4172d1d418eSSumit Saxena 
4182d1d418eSSumit Saxena 	req_entry = (U8 *)op_req_q->q_base + (pi * req_sz);
4192d1d418eSSumit Saxena 	memset(req_entry, 0, req_sz);
4202d1d418eSSumit Saxena 	memcpy(req_entry, req, MPI3MR_AREQ_FRAME_SZ);
4212d1d418eSSumit Saxena 	if (++pi == max_entries)
4222d1d418eSSumit Saxena 		pi = 0;
4232d1d418eSSumit Saxena 	op_req_q->pi = pi;
4242d1d418eSSumit Saxena 
4252d1d418eSSumit Saxena 	mpi3mr_atomic_inc(&sc->op_reply_q[op_req_q->reply_qid - 1].pend_ios);
4262d1d418eSSumit Saxena 
4272d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_OPER_REQ_Q_N_PI_OFFSET(op_req_q->qid), op_req_q->pi);
4282d1d418eSSumit Saxena 	if (sc->mpi3mr_debug & MPI3MR_TRACE) {
4292d1d418eSSumit Saxena 		device_printf(sc->mpi3mr_dev, "IO submission: QID:%d PI:0x%x\n", op_req_q->qid, op_req_q->pi);
4302d1d418eSSumit Saxena 		mpi3mr_hexdump(req_entry, MPI3MR_AREQ_FRAME_SZ, 8);
4312d1d418eSSumit Saxena 	}
4322d1d418eSSumit Saxena 
4332d1d418eSSumit Saxena out:
4342d1d418eSSumit Saxena 	mtx_unlock_spin(&op_req_q->q_lock);
4352d1d418eSSumit Saxena 	return retval;
4362d1d418eSSumit Saxena }
4372d1d418eSSumit Saxena 
4382d1d418eSSumit Saxena inline void
4392d1d418eSSumit Saxena mpi3mr_add_sg_single(void *paddr, U8 flags, U32 length,
4402d1d418eSSumit Saxena 		     bus_addr_t dma_addr)
4412d1d418eSSumit Saxena {
4422d1d418eSSumit Saxena 	Mpi3SGESimple_t *sgel = paddr;
4432d1d418eSSumit Saxena 
4442d1d418eSSumit Saxena 	sgel->Flags = flags;
4452d1d418eSSumit Saxena 	sgel->Length = (length);
4462d1d418eSSumit Saxena 	sgel->Address = (U64)dma_addr;
4472d1d418eSSumit Saxena }
4482d1d418eSSumit Saxena 
4492d1d418eSSumit Saxena void mpi3mr_build_zero_len_sge(void *paddr)
4502d1d418eSSumit Saxena {
4512d1d418eSSumit Saxena 	U8 sgl_flags = (MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE |
4522d1d418eSSumit Saxena 		MPI3_SGE_FLAGS_DLAS_SYSTEM | MPI3_SGE_FLAGS_END_OF_LIST);
4532d1d418eSSumit Saxena 
4542d1d418eSSumit Saxena 	mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1);
4552d1d418eSSumit Saxena 
4562d1d418eSSumit Saxena }
4572d1d418eSSumit Saxena 
4582d1d418eSSumit Saxena void mpi3mr_enable_interrupts(struct mpi3mr_softc *sc)
4592d1d418eSSumit Saxena {
4602d1d418eSSumit Saxena 	sc->intr_enabled = 1;
4612d1d418eSSumit Saxena }
4622d1d418eSSumit Saxena 
4632d1d418eSSumit Saxena void mpi3mr_disable_interrupts(struct mpi3mr_softc *sc)
4642d1d418eSSumit Saxena {
4652d1d418eSSumit Saxena 	sc->intr_enabled = 0;
4662d1d418eSSumit Saxena }
4672d1d418eSSumit Saxena 
4682d1d418eSSumit Saxena void
4692d1d418eSSumit Saxena mpi3mr_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
4702d1d418eSSumit Saxena {
4712d1d418eSSumit Saxena 	bus_addr_t *addr;
4722d1d418eSSumit Saxena 
4732d1d418eSSumit Saxena 	addr = arg;
4742d1d418eSSumit Saxena 	*addr = segs[0].ds_addr;
4752d1d418eSSumit Saxena }
4762d1d418eSSumit Saxena 
4772d1d418eSSumit Saxena static int mpi3mr_delete_op_reply_queue(struct mpi3mr_softc *sc, U16 qid)
4782d1d418eSSumit Saxena {
4792d1d418eSSumit Saxena 	Mpi3DeleteReplyQueueRequest_t delq_req;
4802d1d418eSSumit Saxena 	struct mpi3mr_op_reply_queue *op_reply_q;
4812d1d418eSSumit Saxena 	int retval = 0;
4822d1d418eSSumit Saxena 
4832d1d418eSSumit Saxena 
4842d1d418eSSumit Saxena 	op_reply_q = &sc->op_reply_q[qid - 1];
4852d1d418eSSumit Saxena 
4862d1d418eSSumit Saxena 	if (!op_reply_q->qid)
4872d1d418eSSumit Saxena 	{
4882d1d418eSSumit Saxena 		retval = -1;
4892d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: called with invalid Reply QID\n",
4902d1d418eSSumit Saxena 		    sc->name);
4912d1d418eSSumit Saxena 		goto out;
4922d1d418eSSumit Saxena 	}
4932d1d418eSSumit Saxena 
4942d1d418eSSumit Saxena 	memset(&delq_req, 0, sizeof(delq_req));
4952d1d418eSSumit Saxena 
4962d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
4972d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
4982d1d418eSSumit Saxena 		retval = -1;
4992d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: Init command is in use\n",
5002d1d418eSSumit Saxena 		    sc->name);
5012d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
5022d1d418eSSumit Saxena 		goto out;
5032d1d418eSSumit Saxena 	}
5042d1d418eSSumit Saxena 
5052d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
5062d1d418eSSumit Saxena 		retval = -1;
5072d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: Init command is in use\n",
5082d1d418eSSumit Saxena 		    sc->name);
5092d1d418eSSumit Saxena 		goto out;
5102d1d418eSSumit Saxena 	}
5112d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
5122d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
5132d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
5142d1d418eSSumit Saxena 	delq_req.HostTag = MPI3MR_HOSTTAG_INITCMDS;
5152d1d418eSSumit Saxena 	delq_req.Function = MPI3_FUNCTION_DELETE_REPLY_QUEUE;
5162d1d418eSSumit Saxena 	delq_req.QueueID = qid;
5172d1d418eSSumit Saxena 
5182d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
5192d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &delq_req, sizeof(delq_req));
5202d1d418eSSumit Saxena 	if (retval) {
5212d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: Admin Post failed\n",
5222d1d418eSSumit Saxena 		    sc->name);
5232d1d418eSSumit Saxena 		goto out_unlock;
5242d1d418eSSumit Saxena 	}
5252d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
5262d1d418eSSumit Saxena 	    (MPI3MR_INTADMCMD_TIMEOUT));
5272d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
5282d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: command timed out\n",
5292d1d418eSSumit Saxena 		    sc->name);
5302d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
5312d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_DELREPQ_TIMEOUT);
5322d1d418eSSumit Saxena 		sc->unrecoverable = 1;
5332d1d418eSSumit Saxena 
5342d1d418eSSumit Saxena 		retval = -1;
5352d1d418eSSumit Saxena 		goto out_unlock;
5362d1d418eSSumit Saxena 	}
5372d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
5382d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
5392d1d418eSSumit Saxena 		printf(IOCNAME "Issue DelRepQ: Failed IOCStatus(0x%04x) "
5402d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
5412d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
5422d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
5432d1d418eSSumit Saxena 		retval = -1;
5442d1d418eSSumit Saxena 		goto out_unlock;
5452d1d418eSSumit Saxena 	}
5462d1d418eSSumit Saxena 	sc->irq_ctx[qid - 1].op_reply_q = NULL;
5472d1d418eSSumit Saxena 
5482d1d418eSSumit Saxena 	if (sc->op_reply_q[qid - 1].q_base_phys != 0)
5492d1d418eSSumit Saxena 		bus_dmamap_unload(sc->op_reply_q[qid - 1].q_base_tag, sc->op_reply_q[qid - 1].q_base_dmamap);
5502d1d418eSSumit Saxena 	if (sc->op_reply_q[qid - 1].q_base != NULL)
5512d1d418eSSumit 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);
5522d1d418eSSumit Saxena 	if (sc->op_reply_q[qid - 1].q_base_tag != NULL)
5532d1d418eSSumit Saxena 		bus_dma_tag_destroy(sc->op_reply_q[qid - 1].q_base_tag);
5542d1d418eSSumit Saxena 
5552d1d418eSSumit Saxena 	sc->op_reply_q[qid - 1].q_base = NULL;
5562d1d418eSSumit Saxena 	sc->op_reply_q[qid - 1].qid = 0;
5572d1d418eSSumit Saxena out_unlock:
5582d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
5592d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
5602d1d418eSSumit Saxena out:
5612d1d418eSSumit Saxena 	return retval;
5622d1d418eSSumit Saxena }
5632d1d418eSSumit Saxena 
5642d1d418eSSumit Saxena /**
5652d1d418eSSumit Saxena  * mpi3mr_create_op_reply_queue - create operational reply queue
5662d1d418eSSumit Saxena  * @sc: Adapter instance reference
5672d1d418eSSumit Saxena  * @qid: operational reply queue id
5682d1d418eSSumit Saxena  *
5692d1d418eSSumit Saxena  * Create operatinal reply queue by issuing MPI request
5702d1d418eSSumit Saxena  * through admin queue.
5712d1d418eSSumit Saxena  *
5722d1d418eSSumit Saxena  * Return:  0 on success, non-zero on failure.
5732d1d418eSSumit Saxena  */
5742d1d418eSSumit Saxena static int mpi3mr_create_op_reply_queue(struct mpi3mr_softc *sc, U16 qid)
5752d1d418eSSumit Saxena {
5762d1d418eSSumit Saxena 	Mpi3CreateReplyQueueRequest_t create_req;
5772d1d418eSSumit Saxena 	struct mpi3mr_op_reply_queue *op_reply_q;
5782d1d418eSSumit Saxena 	int retval = 0;
5792d1d418eSSumit Saxena 	char q_lock_name[32];
5802d1d418eSSumit Saxena 
5812d1d418eSSumit Saxena 	op_reply_q = &sc->op_reply_q[qid - 1];
5822d1d418eSSumit Saxena 
5832d1d418eSSumit Saxena 	if (op_reply_q->qid)
5842d1d418eSSumit Saxena 	{
5852d1d418eSSumit Saxena 		retval = -1;
5862d1d418eSSumit Saxena 		printf(IOCNAME "CreateRepQ: called for duplicate qid %d\n",
5872d1d418eSSumit Saxena 		    sc->name, op_reply_q->qid);
5882d1d418eSSumit Saxena 		return retval;
5892d1d418eSSumit Saxena 	}
5902d1d418eSSumit Saxena 
5912d1d418eSSumit Saxena 	op_reply_q->ci = 0;
5922d1d418eSSumit Saxena 	if (pci_get_revid(sc->mpi3mr_dev) == SAS4116_CHIP_REV_A0)
5932d1d418eSSumit Saxena 		op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD_A0;
5942d1d418eSSumit Saxena 	else
5952d1d418eSSumit Saxena 		op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
5962d1d418eSSumit Saxena 
5972d1d418eSSumit Saxena 	op_reply_q->qsz = op_reply_q->num_replies * sc->op_reply_sz;
5982d1d418eSSumit Saxena 	op_reply_q->ephase = 1;
5992d1d418eSSumit Saxena 
6002d1d418eSSumit Saxena         if (!op_reply_q->q_base) {
6012d1d418eSSumit Saxena 		snprintf(q_lock_name, 32, "Reply Queue Lock[%d]", qid);
6022d1d418eSSumit Saxena 		mtx_init(&op_reply_q->q_lock, q_lock_name, NULL, MTX_SPIN);
6032d1d418eSSumit Saxena 
6042d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
6052d1d418eSSumit Saxena 					4, 0,			/* algnmnt, boundary */
6062d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
6072d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR,	/* highaddr */
6082d1d418eSSumit Saxena 					NULL, NULL,		/* filter, filterarg */
6092d1d418eSSumit Saxena 					op_reply_q->qsz,		/* maxsize */
6102d1d418eSSumit Saxena 					1,			/* nsegments */
6112d1d418eSSumit Saxena 					op_reply_q->qsz,		/* maxsegsize */
6122d1d418eSSumit Saxena 					0,			/* flags */
6132d1d418eSSumit Saxena 					NULL, NULL,		/* lockfunc, lockarg */
6142d1d418eSSumit Saxena 					&op_reply_q->q_base_tag)) {
6152d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Operational reply DMA tag\n");
6162d1d418eSSumit Saxena 			return (ENOMEM);
6172d1d418eSSumit Saxena 		}
6182d1d418eSSumit Saxena 
6192d1d418eSSumit Saxena 		if (bus_dmamem_alloc(op_reply_q->q_base_tag, (void **)&op_reply_q->q_base,
6202d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &op_reply_q->q_base_dmamap)) {
6212d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
6222d1d418eSSumit Saxena 			return (ENOMEM);
6232d1d418eSSumit Saxena 		}
6242d1d418eSSumit Saxena 		bzero(op_reply_q->q_base, op_reply_q->qsz);
6252d1d418eSSumit 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,
6262d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &op_reply_q->q_base_phys, 0);
6272d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Operational Reply queue ID: %d phys addr= %#016jx virt_addr: %pa size= %d\n",
6282d1d418eSSumit Saxena 		    qid, (uintmax_t)op_reply_q->q_base_phys, op_reply_q->q_base, op_reply_q->qsz);
6292d1d418eSSumit Saxena 
6302d1d418eSSumit Saxena 		if (!op_reply_q->q_base)
6312d1d418eSSumit Saxena 		{
6322d1d418eSSumit Saxena 			retval = -1;
6332d1d418eSSumit Saxena 			printf(IOCNAME "CreateRepQ: memory alloc failed for qid %d\n",
6342d1d418eSSumit Saxena 			    sc->name, qid);
6352d1d418eSSumit Saxena 			goto out;
6362d1d418eSSumit Saxena 		}
6372d1d418eSSumit Saxena 	}
6382d1d418eSSumit Saxena 
6392d1d418eSSumit Saxena 	memset(&create_req, 0, sizeof(create_req));
6402d1d418eSSumit Saxena 
6412d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
6422d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
6432d1d418eSSumit Saxena 		retval = -1;
6442d1d418eSSumit Saxena 		printf(IOCNAME "CreateRepQ: Init command is in use\n",
6452d1d418eSSumit Saxena 		    sc->name);
6462d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
6472d1d418eSSumit Saxena 		goto out;
6482d1d418eSSumit Saxena 	}
6492d1d418eSSumit Saxena 
6502d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
6512d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
6522d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
6532d1d418eSSumit Saxena 	create_req.HostTag = MPI3MR_HOSTTAG_INITCMDS;
6542d1d418eSSumit Saxena 	create_req.Function = MPI3_FUNCTION_CREATE_REPLY_QUEUE;
6552d1d418eSSumit Saxena 	create_req.QueueID = qid;
6562d1d418eSSumit Saxena 	create_req.Flags = MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE;
6572d1d418eSSumit Saxena 	create_req.MSIxIndex = sc->irq_ctx[qid - 1].msix_index;
6582d1d418eSSumit Saxena 	create_req.BaseAddress = (U64)op_reply_q->q_base_phys;
6592d1d418eSSumit Saxena 	create_req.Size = op_reply_q->num_replies;
6602d1d418eSSumit Saxena 
6612d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
6622d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &create_req,
6632d1d418eSSumit Saxena 	    sizeof(create_req));
6642d1d418eSSumit Saxena 	if (retval) {
6652d1d418eSSumit Saxena 		printf(IOCNAME "CreateRepQ: Admin Post failed\n",
6662d1d418eSSumit Saxena 		    sc->name);
6672d1d418eSSumit Saxena 		goto out_unlock;
6682d1d418eSSumit Saxena 	}
6692d1d418eSSumit Saxena 
6702d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
6712d1d418eSSumit Saxena 	  	MPI3MR_INTADMCMD_TIMEOUT);
6722d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
6732d1d418eSSumit Saxena 		printf(IOCNAME "CreateRepQ: command timed out\n",
6742d1d418eSSumit Saxena 		    sc->name);
6752d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
6762d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT);
6772d1d418eSSumit Saxena 		sc->unrecoverable = 1;
6782d1d418eSSumit Saxena 		retval = -1;
6792d1d418eSSumit Saxena 		goto out_unlock;
6802d1d418eSSumit Saxena 	}
6812d1d418eSSumit Saxena 
6822d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
6832d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
6842d1d418eSSumit Saxena 		printf(IOCNAME "CreateRepQ: Failed IOCStatus(0x%04x) "
6852d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
6862d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
6872d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
6882d1d418eSSumit Saxena 		retval = -1;
6892d1d418eSSumit Saxena 		goto out_unlock;
6902d1d418eSSumit Saxena 	}
6912d1d418eSSumit Saxena 	op_reply_q->qid = qid;
6922d1d418eSSumit Saxena 	sc->irq_ctx[qid - 1].op_reply_q = op_reply_q;
6932d1d418eSSumit Saxena 
6942d1d418eSSumit Saxena out_unlock:
6952d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
6962d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
6972d1d418eSSumit Saxena out:
6982d1d418eSSumit Saxena 	if (retval) {
6992d1d418eSSumit Saxena 		if (op_reply_q->q_base_phys != 0)
7002d1d418eSSumit Saxena 			bus_dmamap_unload(op_reply_q->q_base_tag, op_reply_q->q_base_dmamap);
7012d1d418eSSumit Saxena 		if (op_reply_q->q_base != NULL)
7022d1d418eSSumit Saxena 			bus_dmamem_free(op_reply_q->q_base_tag, op_reply_q->q_base, op_reply_q->q_base_dmamap);
7032d1d418eSSumit Saxena 		if (op_reply_q->q_base_tag != NULL)
7042d1d418eSSumit Saxena 			bus_dma_tag_destroy(op_reply_q->q_base_tag);
7052d1d418eSSumit Saxena 		op_reply_q->q_base = NULL;
7062d1d418eSSumit Saxena 		op_reply_q->qid = 0;
7072d1d418eSSumit Saxena 	}
7082d1d418eSSumit Saxena 
7092d1d418eSSumit Saxena 	return retval;
7102d1d418eSSumit Saxena }
7112d1d418eSSumit Saxena 
7122d1d418eSSumit Saxena /**
7132d1d418eSSumit Saxena  * mpi3mr_create_op_req_queue - create operational request queue
7142d1d418eSSumit Saxena  * @sc: Adapter instance reference
7152d1d418eSSumit Saxena  * @req_qid: operational request queue id
7162d1d418eSSumit Saxena  * @reply_qid: Reply queue ID
7172d1d418eSSumit Saxena  *
7182d1d418eSSumit Saxena  * Create operatinal request queue by issuing MPI request
7192d1d418eSSumit Saxena  * through admin queue.
7202d1d418eSSumit Saxena  *
7212d1d418eSSumit Saxena  * Return:  0 on success, non-zero on failure.
7222d1d418eSSumit Saxena  */
7232d1d418eSSumit Saxena static int mpi3mr_create_op_req_queue(struct mpi3mr_softc *sc, U16 req_qid, U8 reply_qid)
7242d1d418eSSumit Saxena {
7252d1d418eSSumit Saxena 	Mpi3CreateRequestQueueRequest_t create_req;
7262d1d418eSSumit Saxena 	struct mpi3mr_op_req_queue *op_req_q;
7272d1d418eSSumit Saxena 	int retval = 0;
7282d1d418eSSumit Saxena 	char q_lock_name[32];
7292d1d418eSSumit Saxena 
7302d1d418eSSumit Saxena 	op_req_q = &sc->op_req_q[req_qid - 1];
7312d1d418eSSumit Saxena 
7322d1d418eSSumit Saxena 	if (op_req_q->qid)
7332d1d418eSSumit Saxena 	{
7342d1d418eSSumit Saxena 		retval = -1;
7352d1d418eSSumit Saxena 		printf(IOCNAME "CreateReqQ: called for duplicate qid %d\n",
7362d1d418eSSumit Saxena 		    sc->name, op_req_q->qid);
7372d1d418eSSumit Saxena 		return retval;
7382d1d418eSSumit Saxena 	}
7392d1d418eSSumit Saxena 
7402d1d418eSSumit Saxena 	op_req_q->ci = 0;
7412d1d418eSSumit Saxena 	op_req_q->pi = 0;
7422d1d418eSSumit Saxena 	op_req_q->num_reqs = MPI3MR_OP_REQ_Q_QD;
7432d1d418eSSumit Saxena 	op_req_q->qsz = op_req_q->num_reqs * sc->facts.op_req_sz;
7442d1d418eSSumit Saxena 	op_req_q->reply_qid = reply_qid;
7452d1d418eSSumit Saxena 
7462d1d418eSSumit Saxena 	if (!op_req_q->q_base) {
7472d1d418eSSumit Saxena 		snprintf(q_lock_name, 32, "Request Queue Lock[%d]", req_qid);
7482d1d418eSSumit Saxena 		mtx_init(&op_req_q->q_lock, q_lock_name, NULL, MTX_SPIN);
7492d1d418eSSumit Saxena 
7502d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
7512d1d418eSSumit Saxena 					4, 0,			/* algnmnt, boundary */
7522d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
7532d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR,	/* highaddr */
7542d1d418eSSumit Saxena 					NULL, NULL,		/* filter, filterarg */
7552d1d418eSSumit Saxena 					op_req_q->qsz,		/* maxsize */
7562d1d418eSSumit Saxena 					1,			/* nsegments */
7572d1d418eSSumit Saxena 					op_req_q->qsz,		/* maxsegsize */
7582d1d418eSSumit Saxena 					0,			/* flags */
7592d1d418eSSumit Saxena 					NULL, NULL,		/* lockfunc, lockarg */
7602d1d418eSSumit Saxena 					&op_req_q->q_base_tag)) {
7612d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
7622d1d418eSSumit Saxena 			return (ENOMEM);
7632d1d418eSSumit Saxena 		}
7642d1d418eSSumit Saxena 
7652d1d418eSSumit Saxena 		if (bus_dmamem_alloc(op_req_q->q_base_tag, (void **)&op_req_q->q_base,
7662d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &op_req_q->q_base_dmamap)) {
7672d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
7682d1d418eSSumit Saxena 			return (ENOMEM);
7692d1d418eSSumit Saxena 		}
7702d1d418eSSumit Saxena 
7712d1d418eSSumit Saxena 		bzero(op_req_q->q_base, op_req_q->qsz);
7722d1d418eSSumit Saxena 
7732d1d418eSSumit 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,
7742d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &op_req_q->q_base_phys, 0);
7752d1d418eSSumit Saxena 
7762d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Operational Request QID: %d phys addr= %#016jx virt addr= %pa size= %d associated Reply QID: %d\n",
7772d1d418eSSumit Saxena 		    req_qid, (uintmax_t)op_req_q->q_base_phys, op_req_q->q_base, op_req_q->qsz, reply_qid);
7782d1d418eSSumit Saxena 
7792d1d418eSSumit Saxena 		if (!op_req_q->q_base) {
7802d1d418eSSumit Saxena 			retval = -1;
7812d1d418eSSumit Saxena 			printf(IOCNAME "CreateReqQ: memory alloc failed for qid %d\n",
7822d1d418eSSumit Saxena 			    sc->name, req_qid);
7832d1d418eSSumit Saxena 			goto out;
7842d1d418eSSumit Saxena 		}
7852d1d418eSSumit Saxena 	}
7862d1d418eSSumit Saxena 
7872d1d418eSSumit Saxena 	memset(&create_req, 0, sizeof(create_req));
7882d1d418eSSumit Saxena 
7892d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
7902d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
7912d1d418eSSumit Saxena 		retval = -1;
7922d1d418eSSumit Saxena 		printf(IOCNAME "CreateReqQ: Init command is in use\n",
7932d1d418eSSumit Saxena 		    sc->name);
7942d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
7952d1d418eSSumit Saxena 		goto out;
7962d1d418eSSumit Saxena 	}
7972d1d418eSSumit Saxena 
7982d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
7992d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
8002d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
8012d1d418eSSumit Saxena 	create_req.HostTag = MPI3MR_HOSTTAG_INITCMDS;
8022d1d418eSSumit Saxena 	create_req.Function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE;
8032d1d418eSSumit Saxena 	create_req.QueueID = req_qid;
8042d1d418eSSumit Saxena 	create_req.Flags = 0;
8052d1d418eSSumit Saxena 	create_req.ReplyQueueID = reply_qid;
8062d1d418eSSumit Saxena 	create_req.BaseAddress = (U64)op_req_q->q_base_phys;
8072d1d418eSSumit Saxena 	create_req.Size = op_req_q->num_reqs;
8082d1d418eSSumit Saxena 
8092d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
8102d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &create_req,
8112d1d418eSSumit Saxena 	    sizeof(create_req));
8122d1d418eSSumit Saxena 	if (retval) {
8132d1d418eSSumit Saxena 		printf(IOCNAME "CreateReqQ: Admin Post failed\n",
8142d1d418eSSumit Saxena 		    sc->name);
8152d1d418eSSumit Saxena 		goto out_unlock;
8162d1d418eSSumit Saxena 	}
8172d1d418eSSumit Saxena 
8182d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
8192d1d418eSSumit Saxena 	    (MPI3MR_INTADMCMD_TIMEOUT));
8202d1d418eSSumit Saxena 
8212d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
8222d1d418eSSumit Saxena 		printf(IOCNAME "CreateReqQ: command timed out\n",
8232d1d418eSSumit Saxena 		    sc->name);
8242d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
8252d1d418eSSumit Saxena 			MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT);
8262d1d418eSSumit Saxena 		sc->unrecoverable = 1;
8272d1d418eSSumit Saxena 		retval = -1;
8282d1d418eSSumit Saxena 		goto out_unlock;
8292d1d418eSSumit Saxena 	}
8302d1d418eSSumit Saxena 
8312d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
8322d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
8332d1d418eSSumit Saxena 		printf(IOCNAME "CreateReqQ: Failed IOCStatus(0x%04x) "
8342d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
8352d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
8362d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
8372d1d418eSSumit Saxena 		retval = -1;
8382d1d418eSSumit Saxena 		goto out_unlock;
8392d1d418eSSumit Saxena 	}
8402d1d418eSSumit Saxena 	op_req_q->qid = req_qid;
8412d1d418eSSumit Saxena 
8422d1d418eSSumit Saxena out_unlock:
8432d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
8442d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
8452d1d418eSSumit Saxena out:
8462d1d418eSSumit Saxena 	if (retval) {
8472d1d418eSSumit Saxena 		if (op_req_q->q_base_phys != 0)
8482d1d418eSSumit Saxena 			bus_dmamap_unload(op_req_q->q_base_tag, op_req_q->q_base_dmamap);
8492d1d418eSSumit Saxena 		if (op_req_q->q_base != NULL)
8502d1d418eSSumit Saxena 			bus_dmamem_free(op_req_q->q_base_tag, op_req_q->q_base, op_req_q->q_base_dmamap);
8512d1d418eSSumit Saxena 		if (op_req_q->q_base_tag != NULL)
8522d1d418eSSumit Saxena 			bus_dma_tag_destroy(op_req_q->q_base_tag);
8532d1d418eSSumit Saxena 		op_req_q->q_base = NULL;
8542d1d418eSSumit Saxena 		op_req_q->qid = 0;
8552d1d418eSSumit Saxena 	}
8562d1d418eSSumit Saxena 	return retval;
8572d1d418eSSumit Saxena }
8582d1d418eSSumit Saxena 
8592d1d418eSSumit Saxena /**
8602d1d418eSSumit Saxena  * mpi3mr_create_op_queues - create operational queues
8612d1d418eSSumit Saxena  * @sc: Adapter instance reference
8622d1d418eSSumit Saxena  *
8632d1d418eSSumit Saxena  * Create operatinal queues(request queues and reply queues).
8642d1d418eSSumit Saxena  * Return:  0 on success, non-zero on failure.
8652d1d418eSSumit Saxena  */
8662d1d418eSSumit Saxena static int mpi3mr_create_op_queues(struct mpi3mr_softc *sc)
8672d1d418eSSumit Saxena {
8682d1d418eSSumit Saxena 	int retval = 0;
8692d1d418eSSumit Saxena 	U16 num_queues = 0, i = 0, qid;
8702d1d418eSSumit Saxena 
8712d1d418eSSumit Saxena 	num_queues = min(sc->facts.max_op_reply_q,
8722d1d418eSSumit Saxena 	    sc->facts.max_op_req_q);
8732d1d418eSSumit Saxena 	num_queues = min(num_queues, sc->msix_count);
8742d1d418eSSumit Saxena 
8752d1d418eSSumit Saxena 	/*
8762d1d418eSSumit Saxena 	 * During reset set the num_queues to the number of queues
8772d1d418eSSumit Saxena 	 * that was set before the reset.
8782d1d418eSSumit Saxena 	 */
8792d1d418eSSumit Saxena 	if (sc->num_queues)
8802d1d418eSSumit Saxena 		num_queues = sc->num_queues;
8812d1d418eSSumit Saxena 
8822d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "Trying to create %d Operational Q pairs\n",
8832d1d418eSSumit Saxena 	    num_queues);
8842d1d418eSSumit Saxena 
8852d1d418eSSumit Saxena 	if (!sc->op_req_q) {
8862d1d418eSSumit Saxena 		sc->op_req_q = malloc(sizeof(struct mpi3mr_op_req_queue) *
8872d1d418eSSumit Saxena 		    num_queues, M_MPI3MR, M_NOWAIT | M_ZERO);
8882d1d418eSSumit Saxena 
8892d1d418eSSumit Saxena 		if (!sc->op_req_q) {
8902d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to alloc memory for Request queue info\n");
8912d1d418eSSumit Saxena 			retval = -1;
8922d1d418eSSumit Saxena 			goto out_failed;
8932d1d418eSSumit Saxena 		}
8942d1d418eSSumit Saxena 	}
8952d1d418eSSumit Saxena 
8962d1d418eSSumit Saxena 	if (!sc->op_reply_q) {
8972d1d418eSSumit Saxena 		sc->op_reply_q = malloc(sizeof(struct mpi3mr_op_reply_queue) * num_queues,
8982d1d418eSSumit Saxena 			M_MPI3MR, M_NOWAIT | M_ZERO);
8992d1d418eSSumit Saxena 
9002d1d418eSSumit Saxena 		if (!sc->op_reply_q) {
9012d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to alloc memory for Reply queue info\n");
9022d1d418eSSumit Saxena 			retval = -1;
9032d1d418eSSumit Saxena 			goto out_failed;
9042d1d418eSSumit Saxena 		}
9052d1d418eSSumit Saxena 	}
9062d1d418eSSumit Saxena 
9072d1d418eSSumit Saxena 	sc->num_hosttag_op_req_q = (sc->max_host_ios + 1) / num_queues;
9082d1d418eSSumit Saxena 
9092d1d418eSSumit Saxena 	/*Operational Request and reply queue ID starts with 1*/
9102d1d418eSSumit Saxena 	for (i = 0; i < num_queues; i++) {
9112d1d418eSSumit Saxena 		qid = i + 1;
9122d1d418eSSumit Saxena 		if (mpi3mr_create_op_reply_queue(sc, qid)) {
9132d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to create Reply queue %d\n",
9142d1d418eSSumit Saxena 			    qid);
9152d1d418eSSumit Saxena 			break;
9162d1d418eSSumit Saxena 		}
9172d1d418eSSumit Saxena 		if (mpi3mr_create_op_req_queue(sc, qid,
9182d1d418eSSumit Saxena 		    sc->op_reply_q[qid - 1].qid)) {
9192d1d418eSSumit Saxena 			mpi3mr_delete_op_reply_queue(sc, qid);
9202d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to create Request queue %d\n",
9212d1d418eSSumit Saxena 			    qid);
9222d1d418eSSumit Saxena 			break;
9232d1d418eSSumit Saxena 		}
9242d1d418eSSumit Saxena 
9252d1d418eSSumit Saxena 	}
9262d1d418eSSumit Saxena 
9272d1d418eSSumit Saxena 	/* Not even one queue is created successfully*/
9282d1d418eSSumit Saxena         if (i == 0) {
9292d1d418eSSumit Saxena                 retval = -1;
9302d1d418eSSumit Saxena                 goto out_failed;
9312d1d418eSSumit Saxena         }
9322d1d418eSSumit Saxena 
9332d1d418eSSumit Saxena 	if (!sc->num_queues) {
9342d1d418eSSumit Saxena 		sc->num_queues = i;
9352d1d418eSSumit Saxena 	} else {
9362d1d418eSSumit Saxena 		if (num_queues != i) {
9372d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Number of queues (%d) post reset are not same as"
9382d1d418eSSumit Saxena 					"queues allocated (%d) during driver init\n", i, num_queues);
9392d1d418eSSumit Saxena 			goto out_failed;
9402d1d418eSSumit Saxena 		}
9412d1d418eSSumit Saxena 	}
9422d1d418eSSumit Saxena 
9432d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "Successfully created %d Operational Queue pairs\n",
9442d1d418eSSumit Saxena 	    sc->num_queues);
9452d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "Request Queue QD: %d Reply queue QD: %d\n",
9462d1d418eSSumit Saxena 	    sc->op_req_q[0].num_reqs, sc->op_reply_q[0].num_replies);
9472d1d418eSSumit Saxena 
9482d1d418eSSumit Saxena 	return retval;
9492d1d418eSSumit Saxena out_failed:
9502d1d418eSSumit Saxena 	if (sc->op_req_q) {
9512d1d418eSSumit Saxena 		free(sc->op_req_q, M_MPI3MR);
9522d1d418eSSumit Saxena 		sc->op_req_q = NULL;
9532d1d418eSSumit Saxena 	}
9542d1d418eSSumit Saxena 	if (sc->op_reply_q) {
9552d1d418eSSumit Saxena 		free(sc->op_reply_q, M_MPI3MR);
9562d1d418eSSumit Saxena 		sc->op_reply_q = NULL;
9572d1d418eSSumit Saxena 	}
9582d1d418eSSumit Saxena 	return retval;
9592d1d418eSSumit Saxena }
9602d1d418eSSumit Saxena 
9612d1d418eSSumit Saxena /**
9622d1d418eSSumit Saxena  * mpi3mr_setup_admin_qpair - Setup admin queue pairs
9632d1d418eSSumit Saxena  * @sc: Adapter instance reference
9642d1d418eSSumit Saxena  *
9652d1d418eSSumit Saxena  * Allocation and setup admin queues(request queues and reply queues).
9662d1d418eSSumit Saxena  * Return:  0 on success, non-zero on failure.
9672d1d418eSSumit Saxena  */
9682d1d418eSSumit Saxena static int mpi3mr_setup_admin_qpair(struct mpi3mr_softc *sc)
9692d1d418eSSumit Saxena {
9702d1d418eSSumit Saxena 	int retval = 0;
9712d1d418eSSumit Saxena 	U32 num_adm_entries = 0;
9722d1d418eSSumit Saxena 
9732d1d418eSSumit Saxena 	sc->admin_req_q_sz = MPI3MR_AREQQ_SIZE;
9742d1d418eSSumit Saxena 	sc->num_admin_reqs = sc->admin_req_q_sz / MPI3MR_AREQ_FRAME_SZ;
9752d1d418eSSumit Saxena 	sc->admin_req_ci = sc->admin_req_pi = 0;
9762d1d418eSSumit Saxena 
9772d1d418eSSumit Saxena 	sc->admin_reply_q_sz = MPI3MR_AREPQ_SIZE;
9782d1d418eSSumit Saxena 	sc->num_admin_replies = sc->admin_reply_q_sz/ MPI3MR_AREP_FRAME_SZ;
9792d1d418eSSumit Saxena 	sc->admin_reply_ci = 0;
9802d1d418eSSumit Saxena 	sc->admin_reply_ephase = 1;
9812d1d418eSSumit Saxena 
9822d1d418eSSumit Saxena 	if (!sc->admin_req) {
9832d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
9842d1d418eSSumit Saxena 					4, 0,			/* algnmnt, boundary */
9852d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
9862d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR,	/* highaddr */
9872d1d418eSSumit Saxena 					NULL, NULL,		/* filter, filterarg */
9882d1d418eSSumit Saxena 					sc->admin_req_q_sz,	/* maxsize */
9892d1d418eSSumit Saxena 					1,			/* nsegments */
9902d1d418eSSumit Saxena 					sc->admin_req_q_sz,	/* maxsegsize */
9912d1d418eSSumit Saxena 					0,			/* flags */
9922d1d418eSSumit Saxena 					NULL, NULL,		/* lockfunc, lockarg */
9932d1d418eSSumit Saxena 					&sc->admin_req_tag)) {
9942d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
9952d1d418eSSumit Saxena 			return (ENOMEM);
9962d1d418eSSumit Saxena 		}
9972d1d418eSSumit Saxena 
9982d1d418eSSumit Saxena 		if (bus_dmamem_alloc(sc->admin_req_tag, (void **)&sc->admin_req,
9992d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &sc->admin_req_dmamap)) {
10002d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
10012d1d418eSSumit Saxena 			return (ENOMEM);
10022d1d418eSSumit Saxena 		}
10032d1d418eSSumit Saxena 		bzero(sc->admin_req, sc->admin_req_q_sz);
10042d1d418eSSumit Saxena 		bus_dmamap_load(sc->admin_req_tag, sc->admin_req_dmamap, sc->admin_req, sc->admin_req_q_sz,
10052d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &sc->admin_req_phys, 0);
10062d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Admin Req queue phys addr= %#016jx size= %d\n",
10072d1d418eSSumit Saxena 		    (uintmax_t)sc->admin_req_phys, sc->admin_req_q_sz);
10082d1d418eSSumit Saxena 
10092d1d418eSSumit Saxena 		if (!sc->admin_req)
10102d1d418eSSumit Saxena 		{
10112d1d418eSSumit Saxena 			retval = -1;
10122d1d418eSSumit Saxena 			printf(IOCNAME "Memory alloc for AdminReqQ: failed\n",
10132d1d418eSSumit Saxena 			    sc->name);
10142d1d418eSSumit Saxena 			goto out_failed;
10152d1d418eSSumit Saxena 		}
10162d1d418eSSumit Saxena 	}
10172d1d418eSSumit Saxena 
10182d1d418eSSumit Saxena 	if (!sc->admin_reply) {
10192d1d418eSSumit Saxena 		mtx_init(&sc->admin_reply_lock, "Admin Reply Queue Lock", NULL, MTX_SPIN);
10202d1d418eSSumit Saxena 
10212d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
10222d1d418eSSumit Saxena 					4, 0,			/* algnmnt, boundary */
10232d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
10242d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR,	/* highaddr */
10252d1d418eSSumit Saxena 					NULL, NULL,		/* filter, filterarg */
10262d1d418eSSumit Saxena 					sc->admin_reply_q_sz,	/* maxsize */
10272d1d418eSSumit Saxena 					1,			/* nsegments */
10282d1d418eSSumit Saxena 					sc->admin_reply_q_sz,	/* maxsegsize */
10292d1d418eSSumit Saxena 					0,			/* flags */
10302d1d418eSSumit Saxena 					NULL, NULL,		/* lockfunc, lockarg */
10312d1d418eSSumit Saxena 					&sc->admin_reply_tag)) {
10322d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate reply DMA tag\n");
10332d1d418eSSumit Saxena 			return (ENOMEM);
10342d1d418eSSumit Saxena 		}
10352d1d418eSSumit Saxena 
10362d1d418eSSumit Saxena 		if (bus_dmamem_alloc(sc->admin_reply_tag, (void **)&sc->admin_reply,
10372d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &sc->admin_reply_dmamap)) {
10382d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
10392d1d418eSSumit Saxena 			return (ENOMEM);
10402d1d418eSSumit Saxena 		}
10412d1d418eSSumit Saxena 		bzero(sc->admin_reply, sc->admin_reply_q_sz);
10422d1d418eSSumit Saxena 		bus_dmamap_load(sc->admin_reply_tag, sc->admin_reply_dmamap, sc->admin_reply, sc->admin_reply_q_sz,
10432d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &sc->admin_reply_phys, 0);
10442d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Admin Reply queue phys addr= %#016jx size= %d\n",
10452d1d418eSSumit Saxena 		    (uintmax_t)sc->admin_reply_phys, sc->admin_req_q_sz);
10462d1d418eSSumit Saxena 
10472d1d418eSSumit Saxena 
10482d1d418eSSumit Saxena 		if (!sc->admin_reply)
10492d1d418eSSumit Saxena 		{
10502d1d418eSSumit Saxena 			retval = -1;
10512d1d418eSSumit Saxena 			printf(IOCNAME "Memory alloc for AdminRepQ: failed\n",
10522d1d418eSSumit Saxena 			    sc->name);
10532d1d418eSSumit Saxena 			goto out_failed;
10542d1d418eSSumit Saxena 		}
10552d1d418eSSumit Saxena 	}
10562d1d418eSSumit Saxena 
10572d1d418eSSumit Saxena 	num_adm_entries = (sc->num_admin_replies << 16) |
10582d1d418eSSumit Saxena 				(sc->num_admin_reqs);
10592d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_OFFSET, num_adm_entries);
10602d1d418eSSumit Saxena 	mpi3mr_regwrite64(sc, MPI3_SYSIF_ADMIN_REQ_Q_ADDR_LOW_OFFSET, sc->admin_req_phys);
10612d1d418eSSumit Saxena 	mpi3mr_regwrite64(sc, MPI3_SYSIF_ADMIN_REPLY_Q_ADDR_LOW_OFFSET, sc->admin_reply_phys);
10622d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REQ_Q_PI_OFFSET, sc->admin_req_pi);
10632d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REPLY_Q_CI_OFFSET, sc->admin_reply_ci);
10642d1d418eSSumit Saxena 
10652d1d418eSSumit Saxena 	return retval;
10662d1d418eSSumit Saxena 
10672d1d418eSSumit Saxena out_failed:
10682d1d418eSSumit Saxena 	/* Free Admin reply*/
10692d1d418eSSumit Saxena 	if (sc->admin_reply_phys)
10702d1d418eSSumit Saxena 		bus_dmamap_unload(sc->admin_reply_tag, sc->admin_reply_dmamap);
10712d1d418eSSumit Saxena 
10722d1d418eSSumit Saxena 	if (sc->admin_reply != NULL)
10732d1d418eSSumit Saxena 		bus_dmamem_free(sc->admin_reply_tag, sc->admin_reply,
10742d1d418eSSumit Saxena 		    sc->admin_reply_dmamap);
10752d1d418eSSumit Saxena 
10762d1d418eSSumit Saxena 	if (sc->admin_reply_tag != NULL)
10772d1d418eSSumit Saxena 		bus_dma_tag_destroy(sc->admin_reply_tag);
10782d1d418eSSumit Saxena 
10792d1d418eSSumit Saxena 	/* Free Admin request*/
10802d1d418eSSumit Saxena 	if (sc->admin_req_phys)
10812d1d418eSSumit Saxena 		bus_dmamap_unload(sc->admin_req_tag, sc->admin_req_dmamap);
10822d1d418eSSumit Saxena 
10832d1d418eSSumit Saxena 	if (sc->admin_req != NULL)
10842d1d418eSSumit Saxena 		bus_dmamem_free(sc->admin_req_tag, sc->admin_req,
10852d1d418eSSumit Saxena 		    sc->admin_req_dmamap);
10862d1d418eSSumit Saxena 
10872d1d418eSSumit Saxena 	if (sc->admin_req_tag != NULL)
10882d1d418eSSumit Saxena 		bus_dma_tag_destroy(sc->admin_req_tag);
10892d1d418eSSumit Saxena 
10902d1d418eSSumit Saxena 	return retval;
10912d1d418eSSumit Saxena }
10922d1d418eSSumit Saxena 
10932d1d418eSSumit Saxena /**
10942d1d418eSSumit Saxena  * mpi3mr_print_fault_info - Display fault information
10952d1d418eSSumit Saxena  * @sc: Adapter instance reference
10962d1d418eSSumit Saxena  *
10972d1d418eSSumit Saxena  * Display the controller fault information if there is a
10982d1d418eSSumit Saxena  * controller fault.
10992d1d418eSSumit Saxena  *
11002d1d418eSSumit Saxena  * Return: Nothing.
11012d1d418eSSumit Saxena  */
11022d1d418eSSumit Saxena static void mpi3mr_print_fault_info(struct mpi3mr_softc *sc)
11032d1d418eSSumit Saxena {
11042d1d418eSSumit Saxena 	U32 ioc_status, code, code1, code2, code3;
11052d1d418eSSumit Saxena 
11062d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
11072d1d418eSSumit Saxena 
11082d1d418eSSumit Saxena 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
11092d1d418eSSumit Saxena 		code = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_OFFSET) &
11102d1d418eSSumit Saxena 			MPI3_SYSIF_FAULT_CODE_MASK;
11112d1d418eSSumit Saxena 		code1 = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_INFO0_OFFSET);
11122d1d418eSSumit Saxena 		code2 = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_INFO1_OFFSET);
11132d1d418eSSumit Saxena 		code3 = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_INFO2_OFFSET);
11142d1d418eSSumit Saxena 		printf(IOCNAME "fault codes 0x%04x:0x%04x:0x%04x:0x%04x\n",
11152d1d418eSSumit Saxena 		    sc->name, code, code1, code2, code3);
11162d1d418eSSumit Saxena 	}
11172d1d418eSSumit Saxena }
11182d1d418eSSumit Saxena 
11192d1d418eSSumit Saxena enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_softc *sc)
11202d1d418eSSumit Saxena {
11212d1d418eSSumit Saxena 	U32 ioc_status, ioc_control;
11222d1d418eSSumit Saxena 	U8 ready, enabled;
11232d1d418eSSumit Saxena 
11242d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
11252d1d418eSSumit Saxena 	ioc_control = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
11262d1d418eSSumit Saxena 
11272d1d418eSSumit Saxena 	if(sc->unrecoverable)
11282d1d418eSSumit Saxena 		return MRIOC_STATE_UNRECOVERABLE;
11292d1d418eSSumit Saxena 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)
11302d1d418eSSumit Saxena 		return MRIOC_STATE_FAULT;
11312d1d418eSSumit Saxena 
11322d1d418eSSumit Saxena 	ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY);
11332d1d418eSSumit Saxena 	enabled = (ioc_control & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC);
11342d1d418eSSumit Saxena 
11352d1d418eSSumit Saxena 	if (ready && enabled)
11362d1d418eSSumit Saxena 		return MRIOC_STATE_READY;
11372d1d418eSSumit Saxena 	if ((!ready) && (!enabled))
11382d1d418eSSumit Saxena 		return MRIOC_STATE_RESET;
11392d1d418eSSumit Saxena 	if ((!ready) && (enabled))
11402d1d418eSSumit Saxena 		return MRIOC_STATE_BECOMING_READY;
11412d1d418eSSumit Saxena 
11422d1d418eSSumit Saxena 	return MRIOC_STATE_RESET_REQUESTED;
11432d1d418eSSumit Saxena }
11442d1d418eSSumit Saxena 
11452d1d418eSSumit Saxena static inline void mpi3mr_clear_resethistory(struct mpi3mr_softc *sc)
11462d1d418eSSumit Saxena {
11472d1d418eSSumit Saxena         U32 ioc_status;
11482d1d418eSSumit Saxena 
11492d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
11502d1d418eSSumit Saxena         if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
11512d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_STATUS_OFFSET, ioc_status);
11522d1d418eSSumit Saxena 
11532d1d418eSSumit Saxena }
11542d1d418eSSumit Saxena 
11552d1d418eSSumit Saxena /**
11562d1d418eSSumit Saxena  * mpi3mr_mur_ioc - Message unit Reset handler
11572d1d418eSSumit Saxena  * @sc: Adapter instance reference
11582d1d418eSSumit Saxena  * @reset_reason: Reset reason code
11592d1d418eSSumit Saxena  *
11602d1d418eSSumit Saxena  * Issue Message unit Reset to the controller and wait for it to
11612d1d418eSSumit Saxena  * be complete.
11622d1d418eSSumit Saxena  *
11632d1d418eSSumit Saxena  * Return: 0 on success, -1 on failure.
11642d1d418eSSumit Saxena  */
11652d1d418eSSumit Saxena static int mpi3mr_mur_ioc(struct mpi3mr_softc *sc, U32 reset_reason)
11662d1d418eSSumit Saxena {
11672d1d418eSSumit Saxena         U32 ioc_config, timeout, ioc_status;
11682d1d418eSSumit Saxena         int retval = -1;
11692d1d418eSSumit Saxena 
11702d1d418eSSumit Saxena         mpi3mr_dprint(sc, MPI3MR_INFO, "Issuing Message Unit Reset(MUR)\n");
11712d1d418eSSumit Saxena         if (sc->unrecoverable) {
11722d1d418eSSumit Saxena                 mpi3mr_dprint(sc, MPI3MR_ERROR, "IOC is unrecoverable MUR not issued\n");
11732d1d418eSSumit Saxena                 return retval;
11742d1d418eSSumit Saxena         }
11752d1d418eSSumit Saxena         mpi3mr_clear_resethistory(sc);
11762d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_SCRATCHPAD0_OFFSET, reset_reason);
11772d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
11782d1d418eSSumit Saxena         ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
11792d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
11802d1d418eSSumit Saxena 
11812d1d418eSSumit Saxena         timeout = MPI3MR_MUR_TIMEOUT * 10;
11822d1d418eSSumit Saxena         do {
11832d1d418eSSumit Saxena 		ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
11842d1d418eSSumit Saxena                 if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
11852d1d418eSSumit Saxena                         mpi3mr_clear_resethistory(sc);
11862d1d418eSSumit Saxena 			ioc_config =
11872d1d418eSSumit Saxena 				mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
11882d1d418eSSumit Saxena                         if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
11892d1d418eSSumit Saxena                             (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
11902d1d418eSSumit Saxena                             (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) {
11912d1d418eSSumit Saxena                                 retval = 0;
11922d1d418eSSumit Saxena                                 break;
11932d1d418eSSumit Saxena                         }
11942d1d418eSSumit Saxena                 }
11952d1d418eSSumit Saxena                 DELAY(100 * 1000);
11962d1d418eSSumit Saxena         } while (--timeout);
11972d1d418eSSumit Saxena 
11982d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
11992d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
12002d1d418eSSumit Saxena 
12012d1d418eSSumit Saxena         mpi3mr_dprint(sc, MPI3MR_INFO, "IOC Status/Config after %s MUR is (0x%x)/(0x%x)\n",
12022d1d418eSSumit Saxena                 !retval ? "successful":"failed", ioc_status, ioc_config);
12032d1d418eSSumit Saxena         return retval;
12042d1d418eSSumit Saxena }
12052d1d418eSSumit Saxena 
12062d1d418eSSumit Saxena /**
12072d1d418eSSumit Saxena  * mpi3mr_bring_ioc_ready - Bring controller to ready state
12082d1d418eSSumit Saxena  * @sc: Adapter instance reference
12092d1d418eSSumit Saxena  *
12102d1d418eSSumit Saxena  * Set Enable IOC bit in IOC configuration register and wait for
12112d1d418eSSumit Saxena  * the controller to become ready.
12122d1d418eSSumit Saxena  *
12132d1d418eSSumit Saxena  * Return: 0 on success, appropriate error on failure.
12142d1d418eSSumit Saxena  */
12152d1d418eSSumit Saxena static int mpi3mr_bring_ioc_ready(struct mpi3mr_softc *sc)
12162d1d418eSSumit Saxena {
12172d1d418eSSumit Saxena         U32 ioc_config, timeout;
12182d1d418eSSumit Saxena         enum mpi3mr_iocstate current_state;
12192d1d418eSSumit Saxena 
12202d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
12212d1d418eSSumit Saxena         ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
12222d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
12232d1d418eSSumit Saxena 
12242d1d418eSSumit Saxena         timeout = sc->ready_timeout * 10;
12252d1d418eSSumit Saxena         do {
12262d1d418eSSumit Saxena                 current_state = mpi3mr_get_iocstate(sc);
12272d1d418eSSumit Saxena                 if (current_state == MRIOC_STATE_READY)
12282d1d418eSSumit Saxena                         return 0;
12292d1d418eSSumit Saxena                 DELAY(100 * 1000);
12302d1d418eSSumit Saxena         } while (--timeout);
12312d1d418eSSumit Saxena 
12322d1d418eSSumit Saxena         return -1;
12332d1d418eSSumit Saxena }
12342d1d418eSSumit Saxena 
12352d1d418eSSumit Saxena static const struct {
12362d1d418eSSumit Saxena 	enum mpi3mr_iocstate value;
12372d1d418eSSumit Saxena 	char *name;
12382d1d418eSSumit Saxena } mrioc_states[] = {
12392d1d418eSSumit Saxena 	{ MRIOC_STATE_READY, "ready" },
12402d1d418eSSumit Saxena 	{ MRIOC_STATE_FAULT, "fault" },
12412d1d418eSSumit Saxena 	{ MRIOC_STATE_RESET, "reset" },
12422d1d418eSSumit Saxena 	{ MRIOC_STATE_BECOMING_READY, "becoming ready" },
12432d1d418eSSumit Saxena 	{ MRIOC_STATE_RESET_REQUESTED, "reset requested" },
12442d1d418eSSumit Saxena 	{ MRIOC_STATE_COUNT, "Count" },
12452d1d418eSSumit Saxena };
12462d1d418eSSumit Saxena 
12472d1d418eSSumit Saxena static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)
12482d1d418eSSumit Saxena {
12492d1d418eSSumit Saxena 	int i;
12502d1d418eSSumit Saxena 	char *name = NULL;
12512d1d418eSSumit Saxena 
12522d1d418eSSumit Saxena 	for (i = 0; i < MRIOC_STATE_COUNT; i++) {
12532d1d418eSSumit Saxena 		if (mrioc_states[i].value == mrioc_state){
12542d1d418eSSumit Saxena 			name = mrioc_states[i].name;
12552d1d418eSSumit Saxena 			break;
12562d1d418eSSumit Saxena 		}
12572d1d418eSSumit Saxena 	}
12582d1d418eSSumit Saxena 	return name;
12592d1d418eSSumit Saxena }
12602d1d418eSSumit Saxena 
12612d1d418eSSumit Saxena /* Reset reason to name mapper structure*/
12622d1d418eSSumit Saxena static const struct {
12632d1d418eSSumit Saxena 	enum mpi3mr_reset_reason value;
12642d1d418eSSumit Saxena 	char *name;
12652d1d418eSSumit Saxena } mpi3mr_reset_reason_codes[] = {
12662d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" },
12672d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_FAULT_WATCH, "fault" },
12682d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_IOCTL, "application" },
12692d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_EH_HOS, "error handling" },
12702d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" },
12712d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_IOCTL_TIMEOUT, "IOCTL timeout" },
12722d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_SCSIIO_TIMEOUT, "SCSIIO timeout" },
12732d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" },
12742d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" },
12752d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" },
12762d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" },
12772d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" },
12782d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" },
12792d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" },
12802d1d418eSSumit Saxena 	{
12812d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT,
12822d1d418eSSumit Saxena 		"create request queue timeout"
12832d1d418eSSumit Saxena 	},
12842d1d418eSSumit Saxena 	{
12852d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT,
12862d1d418eSSumit Saxena 		"create reply queue timeout"
12872d1d418eSSumit Saxena 	},
12882d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" },
12892d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" },
12902d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" },
12912d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" },
12922d1d418eSSumit Saxena 	{
12932d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_CIACTVRST_TIMER,
12942d1d418eSSumit Saxena 		"component image activation timeout"
12952d1d418eSSumit Saxena 	},
12962d1d418eSSumit Saxena 	{
12972d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT,
12982d1d418eSSumit Saxena 		"get package version timeout"
12992d1d418eSSumit Saxena 	},
13002d1d418eSSumit Saxena 	{
13012d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_PELABORT_TIMEOUT,
13022d1d418eSSumit Saxena 		"persistent event log abort timeout"
13032d1d418eSSumit Saxena 	},
13042d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
13052d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
13062d1d418eSSumit Saxena 	{
13072d1d418eSSumit Saxena 		MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT,
13082d1d418eSSumit Saxena 		"diagnostic buffer post timeout"
13092d1d418eSSumit Saxena 	},
13102d1d418eSSumit Saxena 	{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronus reset" },
13112d1d418eSSumit Saxena 	{ MPI3MR_RESET_REASON_COUNT, "Reset reason count" },
13122d1d418eSSumit Saxena };
13132d1d418eSSumit Saxena 
13142d1d418eSSumit Saxena /**
13152d1d418eSSumit Saxena  * mpi3mr_reset_rc_name - get reset reason code name
13162d1d418eSSumit Saxena  * @reason_code: reset reason code value
13172d1d418eSSumit Saxena  *
13182d1d418eSSumit Saxena  * Map reset reason to an NULL terminated ASCII string
13192d1d418eSSumit Saxena  *
13202d1d418eSSumit Saxena  * Return: Name corresponding to reset reason value or NULL.
13212d1d418eSSumit Saxena  */
13222d1d418eSSumit Saxena static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code)
13232d1d418eSSumit Saxena {
13242d1d418eSSumit Saxena 	int i;
13252d1d418eSSumit Saxena 	char *name = NULL;
13262d1d418eSSumit Saxena 
13272d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_RESET_REASON_COUNT; i++) {
13282d1d418eSSumit Saxena 		if (mpi3mr_reset_reason_codes[i].value == reason_code) {
13292d1d418eSSumit Saxena 			name = mpi3mr_reset_reason_codes[i].name;
13302d1d418eSSumit Saxena 			break;
13312d1d418eSSumit Saxena 		}
13322d1d418eSSumit Saxena 	}
13332d1d418eSSumit Saxena 	return name;
13342d1d418eSSumit Saxena }
13352d1d418eSSumit Saxena 
13362d1d418eSSumit Saxena #define MAX_RESET_TYPE 3
13372d1d418eSSumit Saxena /* Reset type to name mapper structure*/
13382d1d418eSSumit Saxena static const struct {
13392d1d418eSSumit Saxena 	U16 reset_type;
13402d1d418eSSumit Saxena 	char *name;
13412d1d418eSSumit Saxena } mpi3mr_reset_types[] = {
13422d1d418eSSumit Saxena 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" },
13432d1d418eSSumit Saxena 	{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" },
13442d1d418eSSumit Saxena 	{ MAX_RESET_TYPE, "count"}
13452d1d418eSSumit Saxena };
13462d1d418eSSumit Saxena 
13472d1d418eSSumit Saxena /**
13482d1d418eSSumit Saxena  * mpi3mr_reset_type_name - get reset type name
13492d1d418eSSumit Saxena  * @reset_type: reset type value
13502d1d418eSSumit Saxena  *
13512d1d418eSSumit Saxena  * Map reset type to an NULL terminated ASCII string
13522d1d418eSSumit Saxena  *
13532d1d418eSSumit Saxena  * Return: Name corresponding to reset type value or NULL.
13542d1d418eSSumit Saxena  */
13552d1d418eSSumit Saxena static const char *mpi3mr_reset_type_name(U16 reset_type)
13562d1d418eSSumit Saxena {
13572d1d418eSSumit Saxena 	int i;
13582d1d418eSSumit Saxena 	char *name = NULL;
13592d1d418eSSumit Saxena 
13602d1d418eSSumit Saxena 	for (i = 0; i < MAX_RESET_TYPE; i++) {
13612d1d418eSSumit Saxena 		if (mpi3mr_reset_types[i].reset_type == reset_type) {
13622d1d418eSSumit Saxena 			name = mpi3mr_reset_types[i].name;
13632d1d418eSSumit Saxena 			break;
13642d1d418eSSumit Saxena 		}
13652d1d418eSSumit Saxena 	}
13662d1d418eSSumit Saxena 	return name;
13672d1d418eSSumit Saxena }
13682d1d418eSSumit Saxena 
13692d1d418eSSumit Saxena /**
13702d1d418eSSumit Saxena  * mpi3mr_soft_reset_success - Check softreset is success or not
13712d1d418eSSumit Saxena  * @ioc_status: IOC status register value
13722d1d418eSSumit Saxena  * @ioc_config: IOC config register value
13732d1d418eSSumit Saxena  *
13742d1d418eSSumit Saxena  * Check whether the soft reset is successful or not based on
13752d1d418eSSumit Saxena  * IOC status and IOC config register values.
13762d1d418eSSumit Saxena  *
13772d1d418eSSumit Saxena  * Return: True when the soft reset is success, false otherwise.
13782d1d418eSSumit Saxena  */
13792d1d418eSSumit Saxena static inline bool
13802d1d418eSSumit Saxena mpi3mr_soft_reset_success(U32 ioc_status, U32 ioc_config)
13812d1d418eSSumit Saxena {
13822d1d418eSSumit Saxena 	if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
13832d1d418eSSumit Saxena 	    (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
13842d1d418eSSumit Saxena 	    (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
13852d1d418eSSumit Saxena 		return true;
13862d1d418eSSumit Saxena 	return false;
13872d1d418eSSumit Saxena }
13882d1d418eSSumit Saxena 
13892d1d418eSSumit Saxena /**
13902d1d418eSSumit Saxena  * mpi3mr_diagfault_success - Check diag fault is success or not
13912d1d418eSSumit Saxena  * @sc: Adapter reference
13922d1d418eSSumit Saxena  * @ioc_status: IOC status register value
13932d1d418eSSumit Saxena  *
13942d1d418eSSumit Saxena  * Check whether the controller hit diag reset fault code.
13952d1d418eSSumit Saxena  *
13962d1d418eSSumit Saxena  * Return: True when there is diag fault, false otherwise.
13972d1d418eSSumit Saxena  */
13982d1d418eSSumit Saxena static inline bool mpi3mr_diagfault_success(struct mpi3mr_softc *sc,
13992d1d418eSSumit Saxena 	U32 ioc_status)
14002d1d418eSSumit Saxena {
14012d1d418eSSumit Saxena 	U32 fault;
14022d1d418eSSumit Saxena 
14032d1d418eSSumit Saxena 	if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT))
14042d1d418eSSumit Saxena 		return false;
14052d1d418eSSumit Saxena 	fault = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_OFFSET) & MPI3_SYSIF_FAULT_CODE_MASK;
14062d1d418eSSumit Saxena 	if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET)
14072d1d418eSSumit Saxena 		return true;
14082d1d418eSSumit Saxena 	return false;
14092d1d418eSSumit Saxena }
14102d1d418eSSumit Saxena 
14112d1d418eSSumit Saxena /**
14122d1d418eSSumit Saxena  * mpi3mr_issue_iocfacts - Send IOC Facts
14132d1d418eSSumit Saxena  * @sc: Adapter instance reference
14142d1d418eSSumit Saxena  * @facts_data: Cached IOC facts data
14152d1d418eSSumit Saxena  *
14162d1d418eSSumit Saxena  * Issue IOC Facts MPI request through admin queue and wait for
14172d1d418eSSumit Saxena  * the completion of it or time out.
14182d1d418eSSumit Saxena  *
14192d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failures.
14202d1d418eSSumit Saxena  */
14212d1d418eSSumit Saxena static int mpi3mr_issue_iocfacts(struct mpi3mr_softc *sc,
14222d1d418eSSumit Saxena     Mpi3IOCFactsData_t *facts_data)
14232d1d418eSSumit Saxena {
14242d1d418eSSumit Saxena 	Mpi3IOCFactsRequest_t iocfacts_req;
14252d1d418eSSumit Saxena 	bus_dma_tag_t data_tag = NULL;
14262d1d418eSSumit Saxena 	bus_dmamap_t data_map = NULL;
14272d1d418eSSumit Saxena 	bus_addr_t data_phys = 0;
14282d1d418eSSumit Saxena 	void *data = NULL;
14292d1d418eSSumit Saxena 	U32 data_len = sizeof(*facts_data);
14302d1d418eSSumit Saxena 	int retval = 0;
14312d1d418eSSumit Saxena 
14322d1d418eSSumit Saxena 	U8 sgl_flags = (MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE |
14332d1d418eSSumit Saxena                 	MPI3_SGE_FLAGS_DLAS_SYSTEM |
14342d1d418eSSumit Saxena 			MPI3_SGE_FLAGS_END_OF_LIST);
14352d1d418eSSumit Saxena 
14362d1d418eSSumit Saxena 
14372d1d418eSSumit Saxena         if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
14382d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
14392d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
14402d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
14412d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
14422d1d418eSSumit Saxena                                 data_len,		/* maxsize */
14432d1d418eSSumit Saxena                                 1,			/* nsegments */
14442d1d418eSSumit Saxena                                 data_len,		/* maxsegsize */
14452d1d418eSSumit Saxena                                 0,			/* flags */
14462d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
14472d1d418eSSumit Saxena                                 &data_tag)) {
14482d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
14492d1d418eSSumit Saxena 		return (ENOMEM);
14502d1d418eSSumit Saxena         }
14512d1d418eSSumit Saxena 
14522d1d418eSSumit Saxena         if (bus_dmamem_alloc(data_tag, (void **)&data,
14532d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &data_map)) {
14542d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d Data  DMA mem alloc failed\n",
14552d1d418eSSumit Saxena 			__func__, __LINE__);
14562d1d418eSSumit Saxena 		return (ENOMEM);
14572d1d418eSSumit Saxena         }
14582d1d418eSSumit Saxena 
14592d1d418eSSumit Saxena         bzero(data, data_len);
14602d1d418eSSumit Saxena         bus_dmamap_load(data_tag, data_map, data, data_len,
14612d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &data_phys, 0);
14622d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d IOCfacts data phys addr= %#016jx size= %d\n",
14632d1d418eSSumit Saxena 	    __func__, __LINE__, (uintmax_t)data_phys, data_len);
14642d1d418eSSumit Saxena 
14652d1d418eSSumit Saxena 	if (!data)
14662d1d418eSSumit Saxena 	{
14672d1d418eSSumit Saxena 		retval = -1;
14682d1d418eSSumit Saxena 		printf(IOCNAME "Memory alloc for IOCFactsData: failed\n",
14692d1d418eSSumit Saxena 		    sc->name);
14702d1d418eSSumit Saxena 		goto out;
14712d1d418eSSumit Saxena 	}
14722d1d418eSSumit Saxena 
14732d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
14742d1d418eSSumit Saxena 	memset(&iocfacts_req, 0, sizeof(iocfacts_req));
14752d1d418eSSumit Saxena 
14762d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
14772d1d418eSSumit Saxena 		retval = -1;
14782d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCFacts: Init command is in use\n",
14792d1d418eSSumit Saxena 		    sc->name);
14802d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
14812d1d418eSSumit Saxena 		goto out;
14822d1d418eSSumit Saxena 	}
14832d1d418eSSumit Saxena 
14842d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
14852d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
14862d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
14872d1d418eSSumit Saxena 	iocfacts_req.HostTag = (MPI3MR_HOSTTAG_INITCMDS);
14882d1d418eSSumit Saxena 	iocfacts_req.Function = MPI3_FUNCTION_IOC_FACTS;
14892d1d418eSSumit Saxena 
14902d1d418eSSumit Saxena 	mpi3mr_add_sg_single(&iocfacts_req.SGL, sgl_flags, data_len,
14912d1d418eSSumit Saxena 	    data_phys);
14922d1d418eSSumit Saxena 
14932d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
14942d1d418eSSumit Saxena 
14952d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &iocfacts_req,
14962d1d418eSSumit Saxena 	    sizeof(iocfacts_req));
14972d1d418eSSumit Saxena 
14982d1d418eSSumit Saxena 	if (retval) {
14992d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCFacts: Admin Post failed\n",
15002d1d418eSSumit Saxena 		    sc->name);
15012d1d418eSSumit Saxena 		goto out_unlock;
15022d1d418eSSumit Saxena 	}
15032d1d418eSSumit Saxena 
15042d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
15052d1d418eSSumit Saxena 	    (MPI3MR_INTADMCMD_TIMEOUT));
15062d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
15072d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCFacts: command timed out\n",
15082d1d418eSSumit Saxena 		    sc->name);
15092d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
15102d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT);
15112d1d418eSSumit Saxena 		sc->unrecoverable = 1;
15122d1d418eSSumit Saxena 		retval = -1;
15132d1d418eSSumit Saxena 		goto out_unlock;
15142d1d418eSSumit Saxena 	}
15152d1d418eSSumit Saxena 
15162d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
15172d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
15182d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCFacts: Failed IOCStatus(0x%04x) "
15192d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
15202d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
15212d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
15222d1d418eSSumit Saxena 		retval = -1;
15232d1d418eSSumit Saxena 		goto out_unlock;
15242d1d418eSSumit Saxena 	}
15252d1d418eSSumit Saxena 
15262d1d418eSSumit Saxena 	memcpy(facts_data, (U8 *)data, data_len);
15272d1d418eSSumit Saxena out_unlock:
15282d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
15292d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
15302d1d418eSSumit Saxena 
15312d1d418eSSumit Saxena out:
15322d1d418eSSumit Saxena 	if (data_phys != 0)
15332d1d418eSSumit Saxena 		bus_dmamap_unload(data_tag, data_map);
15342d1d418eSSumit Saxena 	if (data != NULL)
15352d1d418eSSumit Saxena 		bus_dmamem_free(data_tag, data, data_map);
15362d1d418eSSumit Saxena 	if (data_tag != NULL)
15372d1d418eSSumit Saxena 		bus_dma_tag_destroy(data_tag);
15382d1d418eSSumit Saxena 	return retval;
15392d1d418eSSumit Saxena }
15402d1d418eSSumit Saxena 
15412d1d418eSSumit Saxena /**
15422d1d418eSSumit Saxena  * mpi3mr_process_factsdata - Process IOC facts data
15432d1d418eSSumit Saxena  * @sc: Adapter instance reference
15442d1d418eSSumit Saxena  * @facts_data: Cached IOC facts data
15452d1d418eSSumit Saxena  *
15462d1d418eSSumit Saxena  * Convert IOC facts data into cpu endianness and cache it in
15472d1d418eSSumit Saxena  * the driver .
15482d1d418eSSumit Saxena  *
15492d1d418eSSumit Saxena  * Return: Nothing.
15502d1d418eSSumit Saxena  */
15512d1d418eSSumit Saxena static int mpi3mr_process_factsdata(struct mpi3mr_softc *sc,
15522d1d418eSSumit Saxena     Mpi3IOCFactsData_t *facts_data)
15532d1d418eSSumit Saxena {
15542d1d418eSSumit Saxena 	int retval = 0;
15552d1d418eSSumit Saxena 	U32 ioc_config, req_sz, facts_flags;
15562d1d418eSSumit Saxena 
15572d1d418eSSumit Saxena 	if (le16toh(facts_data->IOCFactsDataLength) !=
15582d1d418eSSumit Saxena 	    (sizeof(*facts_data) / 4)) {
15592d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "IOCFacts data length mismatch "
15602d1d418eSSumit Saxena 		    " driver_sz(%ld) firmware_sz(%d) \n",
15612d1d418eSSumit Saxena 		    sizeof(*facts_data),
15622d1d418eSSumit Saxena 		    facts_data->IOCFactsDataLength);
15632d1d418eSSumit Saxena 	}
15642d1d418eSSumit Saxena 
15652d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
15662d1d418eSSumit Saxena         req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >>
15672d1d418eSSumit Saxena                   MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT);
15682d1d418eSSumit Saxena 
15692d1d418eSSumit Saxena 	if (facts_data->IOCRequestFrameSize != (req_sz/4)) {
15702d1d418eSSumit Saxena 		 mpi3mr_dprint(sc, MPI3MR_INFO, "IOCFacts data reqFrameSize mismatch "
15712d1d418eSSumit Saxena 		    " hw_size(%d) firmware_sz(%d) \n" , req_sz/4,
15722d1d418eSSumit Saxena 		    facts_data->IOCRequestFrameSize);
15732d1d418eSSumit Saxena 	}
15742d1d418eSSumit Saxena 
15752d1d418eSSumit Saxena 	memset(&sc->facts, 0, sizeof(sc->facts));
15762d1d418eSSumit Saxena 
15772d1d418eSSumit Saxena 	facts_flags = le32toh(facts_data->Flags);
15782d1d418eSSumit Saxena 	sc->facts.op_req_sz = req_sz;
15792d1d418eSSumit Saxena 	sc->op_reply_sz = 1 << ((ioc_config &
15802d1d418eSSumit Saxena                                   MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >>
15812d1d418eSSumit Saxena                                   MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT);
15822d1d418eSSumit Saxena 
15832d1d418eSSumit Saxena 	sc->facts.ioc_num = facts_data->IOCNumber;
15842d1d418eSSumit Saxena         sc->facts.who_init = facts_data->WhoInit;
15852d1d418eSSumit Saxena         sc->facts.max_msix_vectors = facts_data->MaxMSIxVectors;
15862d1d418eSSumit Saxena 	sc->facts.personality = (facts_flags &
15872d1d418eSSumit Saxena 	    MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK);
15882d1d418eSSumit Saxena 	sc->facts.dma_mask = (facts_flags &
15892d1d418eSSumit Saxena 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
15902d1d418eSSumit Saxena 	    MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
15912d1d418eSSumit Saxena         sc->facts.protocol_flags = facts_data->ProtocolFlags;
15922d1d418eSSumit Saxena         sc->facts.mpi_version = (facts_data->MPIVersion.Word);
15932d1d418eSSumit Saxena         sc->facts.max_reqs = (facts_data->MaxOutstandingRequests);
15942d1d418eSSumit Saxena         sc->facts.product_id = (facts_data->ProductID);
15952d1d418eSSumit Saxena 	sc->facts.reply_sz = (facts_data->ReplyFrameSize) * 4;
15962d1d418eSSumit Saxena         sc->facts.exceptions = (facts_data->IOCExceptions);
15972d1d418eSSumit Saxena         sc->facts.max_perids = (facts_data->MaxPersistentID);
15982d1d418eSSumit Saxena         sc->facts.max_vds = (facts_data->MaxVDs);
15992d1d418eSSumit Saxena         sc->facts.max_hpds = (facts_data->MaxHostPDs);
16002d1d418eSSumit Saxena         sc->facts.max_advhpds = (facts_data->MaxAdvHostPDs);
16012d1d418eSSumit Saxena         sc->facts.max_raidpds = (facts_data->MaxRAIDPDs);
16022d1d418eSSumit Saxena         sc->facts.max_nvme = (facts_data->MaxNVMe);
16032d1d418eSSumit Saxena         sc->facts.max_pcieswitches =
16042d1d418eSSumit Saxena                 (facts_data->MaxPCIeSwitches);
16052d1d418eSSumit Saxena         sc->facts.max_sasexpanders =
16062d1d418eSSumit Saxena                 (facts_data->MaxSASExpanders);
16072d1d418eSSumit Saxena         sc->facts.max_sasinitiators =
16082d1d418eSSumit Saxena                 (facts_data->MaxSASInitiators);
16092d1d418eSSumit Saxena         sc->facts.max_enclosures = (facts_data->MaxEnclosures);
16102d1d418eSSumit Saxena         sc->facts.min_devhandle = (facts_data->MinDevHandle);
16112d1d418eSSumit Saxena         sc->facts.max_devhandle = (facts_data->MaxDevHandle);
16122d1d418eSSumit Saxena 	sc->facts.max_op_req_q =
16132d1d418eSSumit Saxena                 (facts_data->MaxOperationalRequestQueues);
16142d1d418eSSumit Saxena 	sc->facts.max_op_reply_q =
16152d1d418eSSumit Saxena                 (facts_data->MaxOperationalReplyQueues);
16162d1d418eSSumit Saxena         sc->facts.ioc_capabilities =
16172d1d418eSSumit Saxena                 (facts_data->IOCCapabilities);
16182d1d418eSSumit Saxena         sc->facts.fw_ver.build_num =
16192d1d418eSSumit Saxena                 (facts_data->FWVersion.BuildNum);
16202d1d418eSSumit Saxena         sc->facts.fw_ver.cust_id =
16212d1d418eSSumit Saxena                 (facts_data->FWVersion.CustomerID);
16222d1d418eSSumit Saxena         sc->facts.fw_ver.ph_minor = facts_data->FWVersion.PhaseMinor;
16232d1d418eSSumit Saxena         sc->facts.fw_ver.ph_major = facts_data->FWVersion.PhaseMajor;
16242d1d418eSSumit Saxena         sc->facts.fw_ver.gen_minor = facts_data->FWVersion.GenMinor;
16252d1d418eSSumit Saxena         sc->facts.fw_ver.gen_major = facts_data->FWVersion.GenMajor;
16262d1d418eSSumit Saxena         sc->max_msix_vectors = min(sc->max_msix_vectors,
16272d1d418eSSumit Saxena             sc->facts.max_msix_vectors);
16282d1d418eSSumit Saxena         sc->facts.sge_mod_mask = facts_data->SGEModifierMask;
16292d1d418eSSumit Saxena         sc->facts.sge_mod_value = facts_data->SGEModifierValue;
16302d1d418eSSumit Saxena         sc->facts.sge_mod_shift = facts_data->SGEModifierShift;
16312d1d418eSSumit Saxena         sc->facts.shutdown_timeout =
16322d1d418eSSumit Saxena                 (facts_data->ShutdownTimeout);
16332d1d418eSSumit Saxena 	sc->facts.max_dev_per_tg = facts_data->MaxDevicesPerThrottleGroup;
16342d1d418eSSumit Saxena 	sc->facts.io_throttle_data_length =
16352d1d418eSSumit Saxena 	    facts_data->IOThrottleDataLength;
16362d1d418eSSumit Saxena 	sc->facts.max_io_throttle_group =
16372d1d418eSSumit Saxena 	    facts_data->MaxIOThrottleGroup;
16382d1d418eSSumit Saxena 	sc->facts.io_throttle_low = facts_data->IOThrottleLow;
16392d1d418eSSumit Saxena 	sc->facts.io_throttle_high = facts_data->IOThrottleHigh;
16402d1d418eSSumit Saxena 
16412d1d418eSSumit Saxena 	/*Store in 512b block count*/
16422d1d418eSSumit Saxena 	if (sc->facts.io_throttle_data_length)
16432d1d418eSSumit Saxena 		sc->io_throttle_data_length =
16442d1d418eSSumit Saxena 		    (sc->facts.io_throttle_data_length * 2 * 4);
16452d1d418eSSumit Saxena 	else
16462d1d418eSSumit Saxena 		/* set the length to 1MB + 1K to disable throttle*/
16472d1d418eSSumit Saxena 		sc->io_throttle_data_length = MPI3MR_MAX_SECTORS + 2;
16482d1d418eSSumit Saxena 
16492d1d418eSSumit Saxena 	sc->io_throttle_high = (sc->facts.io_throttle_high * 2 * 1024);
16502d1d418eSSumit Saxena 	sc->io_throttle_low = (sc->facts.io_throttle_low * 2 * 1024);
16512d1d418eSSumit Saxena 
16522d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),"
16532d1d418eSSumit Saxena             "maxreqs(%d), mindh(%d) maxPDs(%d) maxvectors(%d) maxperids(%d)\n",
16542d1d418eSSumit Saxena 	    sc->facts.ioc_num, sc->facts.max_op_req_q,
16552d1d418eSSumit Saxena 	    sc->facts.max_op_reply_q, sc->facts.max_devhandle,
16562d1d418eSSumit Saxena             sc->facts.max_reqs, sc->facts.min_devhandle,
16572d1d418eSSumit Saxena             sc->facts.max_pds, sc->facts.max_msix_vectors,
16582d1d418eSSumit Saxena             sc->facts.max_perids);
16592d1d418eSSumit Saxena         mpi3mr_dprint(sc, MPI3MR_INFO, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x\n",
16602d1d418eSSumit Saxena             sc->facts.sge_mod_mask, sc->facts.sge_mod_value,
16612d1d418eSSumit Saxena             sc->facts.sge_mod_shift);
16622d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
16632d1d418eSSumit 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",
16642d1d418eSSumit Saxena 	    sc->facts.max_dev_per_tg, sc->facts.max_io_throttle_group,
16652d1d418eSSumit Saxena 	    sc->facts.io_throttle_data_length * 4,
16662d1d418eSSumit Saxena 	    sc->facts.io_throttle_high, sc->facts.io_throttle_low);
16672d1d418eSSumit Saxena 
16682d1d418eSSumit Saxena 	sc->max_host_ios = sc->facts.max_reqs -
16692d1d418eSSumit Saxena 	    (MPI3MR_INTERNALCMDS_RESVD + 1);
16702d1d418eSSumit Saxena 
16712d1d418eSSumit Saxena 	return retval;
16722d1d418eSSumit Saxena }
16732d1d418eSSumit Saxena 
16742d1d418eSSumit Saxena static inline void mpi3mr_setup_reply_free_queues(struct mpi3mr_softc *sc)
16752d1d418eSSumit Saxena {
16762d1d418eSSumit Saxena 	int i;
16772d1d418eSSumit Saxena 	bus_addr_t phys_addr;
16782d1d418eSSumit Saxena 
16792d1d418eSSumit Saxena 	/* initialize Reply buffer Queue */
16802d1d418eSSumit Saxena 	for (i = 0, phys_addr = sc->reply_buf_phys;
16812d1d418eSSumit Saxena 	    i < sc->num_reply_bufs; i++, phys_addr += sc->reply_sz)
16822d1d418eSSumit Saxena 		sc->reply_free_q[i] = phys_addr;
16832d1d418eSSumit Saxena 	sc->reply_free_q[i] = (0);
16842d1d418eSSumit Saxena 
16852d1d418eSSumit Saxena 	/* initialize Sense Buffer Queue */
16862d1d418eSSumit Saxena 	for (i = 0, phys_addr = sc->sense_buf_phys;
16872d1d418eSSumit Saxena 	    i < sc->num_sense_bufs; i++, phys_addr += MPI3MR_SENSEBUF_SZ)
16882d1d418eSSumit Saxena 		sc->sense_buf_q[i] = phys_addr;
16892d1d418eSSumit Saxena 	sc->sense_buf_q[i] = (0);
16902d1d418eSSumit Saxena 
16912d1d418eSSumit Saxena }
16922d1d418eSSumit Saxena 
16932d1d418eSSumit Saxena static int mpi3mr_reply_dma_alloc(struct mpi3mr_softc *sc)
16942d1d418eSSumit Saxena {
16952d1d418eSSumit Saxena 	U32 sz;
16962d1d418eSSumit Saxena 
16972d1d418eSSumit Saxena 	sc->num_reply_bufs = sc->facts.max_reqs + MPI3MR_NUM_EVTREPLIES;
16982d1d418eSSumit Saxena 	sc->reply_free_q_sz = sc->num_reply_bufs + 1;
16992d1d418eSSumit Saxena 	sc->num_sense_bufs = sc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
17002d1d418eSSumit Saxena 	sc->sense_buf_q_sz = sc->num_sense_bufs + 1;
17012d1d418eSSumit Saxena 
17022d1d418eSSumit Saxena 	sz = sc->num_reply_bufs * sc->reply_sz;
17032d1d418eSSumit Saxena 
17042d1d418eSSumit Saxena 	if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,  /* parent */
17052d1d418eSSumit Saxena 				16, 0,			/* algnmnt, boundary */
17062d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
17072d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
17082d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
17092d1d418eSSumit Saxena                                 sz,			/* maxsize */
17102d1d418eSSumit Saxena                                 1,			/* nsegments */
17112d1d418eSSumit Saxena                                 sz,			/* maxsegsize */
17122d1d418eSSumit Saxena                                 0,			/* flags */
17132d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
17142d1d418eSSumit Saxena                                 &sc->reply_buf_tag)) {
17152d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
17162d1d418eSSumit Saxena 		return (ENOMEM);
17172d1d418eSSumit Saxena         }
17182d1d418eSSumit Saxena 
17192d1d418eSSumit Saxena 	if (bus_dmamem_alloc(sc->reply_buf_tag, (void **)&sc->reply_buf,
17202d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &sc->reply_buf_dmamap)) {
17212d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d  DMA mem alloc failed\n",
17222d1d418eSSumit Saxena 			__func__, __LINE__);
17232d1d418eSSumit Saxena 		return (ENOMEM);
17242d1d418eSSumit Saxena         }
17252d1d418eSSumit Saxena 
17262d1d418eSSumit Saxena 	bzero(sc->reply_buf, sz);
17272d1d418eSSumit Saxena         bus_dmamap_load(sc->reply_buf_tag, sc->reply_buf_dmamap, sc->reply_buf, sz,
17282d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &sc->reply_buf_phys, 0);
17292d1d418eSSumit Saxena 
17302d1d418eSSumit Saxena 	sc->reply_buf_dma_min_address = sc->reply_buf_phys;
17312d1d418eSSumit Saxena 	sc->reply_buf_dma_max_address = sc->reply_buf_phys + sz;
17322d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "reply buf (0x%p): depth(%d), frame_size(%d), "
17332d1d418eSSumit Saxena 	    "pool_size(%d kB), reply_buf_dma(0x%llx)\n",
17342d1d418eSSumit Saxena 	    sc->reply_buf, sc->num_reply_bufs, sc->reply_sz,
17352d1d418eSSumit Saxena 	    (sz / 1024), (unsigned long long)sc->reply_buf_phys);
17362d1d418eSSumit Saxena 
17372d1d418eSSumit Saxena 	/* reply free queue, 8 byte align */
17382d1d418eSSumit Saxena 	sz = sc->reply_free_q_sz * 8;
17392d1d418eSSumit Saxena 
17402d1d418eSSumit Saxena         if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
17412d1d418eSSumit Saxena 				8, 0,			/* algnmnt, boundary */
17422d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
17432d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
17442d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
17452d1d418eSSumit Saxena                                 sz,			/* maxsize */
17462d1d418eSSumit Saxena                                 1,			/* nsegments */
17472d1d418eSSumit Saxena                                 sz,			/* maxsegsize */
17482d1d418eSSumit Saxena                                 0,			/* flags */
17492d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
17502d1d418eSSumit Saxena                                 &sc->reply_free_q_tag)) {
17512d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate reply free queue DMA tag\n");
17522d1d418eSSumit Saxena 		return (ENOMEM);
17532d1d418eSSumit Saxena         }
17542d1d418eSSumit Saxena 
17552d1d418eSSumit Saxena         if (bus_dmamem_alloc(sc->reply_free_q_tag, (void **)&sc->reply_free_q,
17562d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &sc->reply_free_q_dmamap)) {
17572d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d  DMA mem alloc failed\n",
17582d1d418eSSumit Saxena 			__func__, __LINE__);
17592d1d418eSSumit Saxena 		return (ENOMEM);
17602d1d418eSSumit Saxena         }
17612d1d418eSSumit Saxena 
17622d1d418eSSumit Saxena 	bzero(sc->reply_free_q, sz);
17632d1d418eSSumit Saxena         bus_dmamap_load(sc->reply_free_q_tag, sc->reply_free_q_dmamap, sc->reply_free_q, sz,
17642d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &sc->reply_free_q_phys, 0);
17652d1d418eSSumit Saxena 
17662d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "reply_free_q (0x%p): depth(%d), frame_size(%d), "
17672d1d418eSSumit Saxena 	    "pool_size(%d kB), reply_free_q_dma(0x%llx)\n",
17682d1d418eSSumit Saxena 	    sc->reply_free_q, sc->reply_free_q_sz, 8, (sz / 1024),
17692d1d418eSSumit Saxena 	    (unsigned long long)sc->reply_free_q_phys);
17702d1d418eSSumit Saxena 
17712d1d418eSSumit Saxena 	/* sense buffer pool,  4 byte align */
17722d1d418eSSumit Saxena 	sz = sc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
17732d1d418eSSumit Saxena 
17742d1d418eSSumit Saxena         if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
17752d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
17762d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
17772d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
17782d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
17792d1d418eSSumit Saxena                                 sz,			/* maxsize */
17802d1d418eSSumit Saxena                                 1,			/* nsegments */
17812d1d418eSSumit Saxena                                 sz,			/* maxsegsize */
17822d1d418eSSumit Saxena                                 0,			/* flags */
17832d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
17842d1d418eSSumit Saxena                                 &sc->sense_buf_tag)) {
17852d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Sense buffer DMA tag\n");
17862d1d418eSSumit Saxena 		return (ENOMEM);
17872d1d418eSSumit Saxena         }
17882d1d418eSSumit Saxena 
17892d1d418eSSumit Saxena 	if (bus_dmamem_alloc(sc->sense_buf_tag, (void **)&sc->sense_buf,
17902d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &sc->sense_buf_dmamap)) {
17912d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d  DMA mem alloc failed\n",
17922d1d418eSSumit Saxena 			__func__, __LINE__);
17932d1d418eSSumit Saxena 		return (ENOMEM);
17942d1d418eSSumit Saxena         }
17952d1d418eSSumit Saxena 
17962d1d418eSSumit Saxena 	bzero(sc->sense_buf, sz);
17972d1d418eSSumit Saxena         bus_dmamap_load(sc->sense_buf_tag, sc->sense_buf_dmamap, sc->sense_buf, sz,
17982d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &sc->sense_buf_phys, 0);
17992d1d418eSSumit Saxena 
18002d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "sense_buf (0x%p): depth(%d), frame_size(%d), "
18012d1d418eSSumit Saxena 	    "pool_size(%d kB), sense_dma(0x%llx)\n",
18022d1d418eSSumit Saxena 	    sc->sense_buf, sc->num_sense_bufs, MPI3MR_SENSEBUF_SZ,
18032d1d418eSSumit Saxena 	    (sz / 1024), (unsigned long long)sc->sense_buf_phys);
18042d1d418eSSumit Saxena 
18052d1d418eSSumit Saxena 	/* sense buffer queue, 8 byte align */
18062d1d418eSSumit Saxena 	sz = sc->sense_buf_q_sz * 8;
18072d1d418eSSumit Saxena 
18082d1d418eSSumit Saxena         if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
18092d1d418eSSumit Saxena 				8, 0,			/* algnmnt, boundary */
18102d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
18112d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
18122d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
18132d1d418eSSumit Saxena                                 sz,			/* maxsize */
18142d1d418eSSumit Saxena                                 1,			/* nsegments */
18152d1d418eSSumit Saxena                                 sz,			/* maxsegsize */
18162d1d418eSSumit Saxena                                 0,			/* flags */
18172d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
18182d1d418eSSumit Saxena                                 &sc->sense_buf_q_tag)) {
18192d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Sense buffer Queue DMA tag\n");
18202d1d418eSSumit Saxena 		return (ENOMEM);
18212d1d418eSSumit Saxena         }
18222d1d418eSSumit Saxena 
18232d1d418eSSumit Saxena 	if (bus_dmamem_alloc(sc->sense_buf_q_tag, (void **)&sc->sense_buf_q,
18242d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &sc->sense_buf_q_dmamap)) {
18252d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d  DMA mem alloc failed\n",
18262d1d418eSSumit Saxena 			__func__, __LINE__);
18272d1d418eSSumit Saxena 		return (ENOMEM);
18282d1d418eSSumit Saxena         }
18292d1d418eSSumit Saxena 
18302d1d418eSSumit Saxena 	bzero(sc->sense_buf_q, sz);
18312d1d418eSSumit Saxena         bus_dmamap_load(sc->sense_buf_q_tag, sc->sense_buf_q_dmamap, sc->sense_buf_q, sz,
18322d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &sc->sense_buf_q_phys, 0);
18332d1d418eSSumit Saxena 
18342d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "sense_buf_q (0x%p): depth(%d), frame_size(%d), "
18352d1d418eSSumit Saxena 	    "pool_size(%d kB), sense_dma(0x%llx)\n",
18362d1d418eSSumit Saxena 	    sc->sense_buf_q, sc->sense_buf_q_sz, 8, (sz / 1024),
18372d1d418eSSumit Saxena 	    (unsigned long long)sc->sense_buf_q_phys);
18382d1d418eSSumit Saxena 
18392d1d418eSSumit Saxena 	return 0;
18402d1d418eSSumit Saxena }
18412d1d418eSSumit Saxena 
18422d1d418eSSumit Saxena static int mpi3mr_reply_alloc(struct mpi3mr_softc *sc)
18432d1d418eSSumit Saxena {
18442d1d418eSSumit Saxena 	int retval = 0;
18452d1d418eSSumit Saxena 	U32 i;
18462d1d418eSSumit Saxena 
18472d1d418eSSumit Saxena 	if (sc->init_cmds.reply)
18482d1d418eSSumit Saxena 		goto post_reply_sbuf;
18492d1d418eSSumit Saxena 
18502d1d418eSSumit Saxena 	sc->init_cmds.reply = malloc(sc->reply_sz,
18512d1d418eSSumit Saxena 		M_MPI3MR, M_NOWAIT | M_ZERO);
18522d1d418eSSumit Saxena 
18532d1d418eSSumit Saxena 	if (!sc->init_cmds.reply) {
18542d1d418eSSumit Saxena 		printf(IOCNAME "Cannot allocate memory for init_cmds.reply\n",
18552d1d418eSSumit Saxena 		    sc->name);
18562d1d418eSSumit Saxena 		goto out_failed;
18572d1d418eSSumit Saxena 	}
18582d1d418eSSumit Saxena 
18592d1d418eSSumit Saxena 	sc->ioctl_cmds.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO);
18602d1d418eSSumit Saxena 	if (!sc->ioctl_cmds.reply) {
18612d1d418eSSumit Saxena 		printf(IOCNAME "Cannot allocate memory for ioctl_cmds.reply\n",
18622d1d418eSSumit Saxena 		    sc->name);
18632d1d418eSSumit Saxena 		goto out_failed;
18642d1d418eSSumit Saxena 	}
18652d1d418eSSumit Saxena 
18662d1d418eSSumit Saxena 	sc->host_tm_cmds.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO);
18672d1d418eSSumit Saxena 	if (!sc->host_tm_cmds.reply) {
18682d1d418eSSumit Saxena 		printf(IOCNAME "Cannot allocate memory for host_tm.reply\n",
18692d1d418eSSumit Saxena 		    sc->name);
18702d1d418eSSumit Saxena 		goto out_failed;
18712d1d418eSSumit Saxena 	}
18722d1d418eSSumit Saxena 	for (i=0; i<MPI3MR_NUM_DEVRMCMD; i++) {
18732d1d418eSSumit Saxena 		sc->dev_rmhs_cmds[i].reply = malloc(sc->reply_sz,
18742d1d418eSSumit Saxena 		    M_MPI3MR, M_NOWAIT | M_ZERO);
18752d1d418eSSumit Saxena 		if (!sc->dev_rmhs_cmds[i].reply) {
18762d1d418eSSumit Saxena 			printf(IOCNAME "Cannot allocate memory for"
18772d1d418eSSumit Saxena 			    " dev_rmhs_cmd[%d].reply\n",
18782d1d418eSSumit Saxena 			    sc->name, i);
18792d1d418eSSumit Saxena 			goto out_failed;
18802d1d418eSSumit Saxena 		}
18812d1d418eSSumit Saxena 	}
18822d1d418eSSumit Saxena 
18832d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
18842d1d418eSSumit Saxena 		sc->evtack_cmds[i].reply = malloc(sc->reply_sz,
18852d1d418eSSumit Saxena 			M_MPI3MR, M_NOWAIT | M_ZERO);
18862d1d418eSSumit Saxena 		if (!sc->evtack_cmds[i].reply)
18872d1d418eSSumit Saxena 			goto out_failed;
18882d1d418eSSumit Saxena 	}
18892d1d418eSSumit Saxena 
18902d1d418eSSumit Saxena 	sc->dev_handle_bitmap_sz = MPI3MR_DIV_ROUND_UP(sc->facts.max_devhandle, 8);
18912d1d418eSSumit Saxena 
18922d1d418eSSumit Saxena 	sc->removepend_bitmap = malloc(sc->dev_handle_bitmap_sz,
18932d1d418eSSumit Saxena 	    M_MPI3MR, M_NOWAIT | M_ZERO);
18942d1d418eSSumit Saxena 	if (!sc->removepend_bitmap) {
18952d1d418eSSumit Saxena 		printf(IOCNAME "Cannot alloc memory for remove pend bitmap\n",
18962d1d418eSSumit Saxena 		    sc->name);
18972d1d418eSSumit Saxena 		goto out_failed;
18982d1d418eSSumit Saxena 	}
18992d1d418eSSumit Saxena 
19002d1d418eSSumit Saxena 	sc->devrem_bitmap_sz = MPI3MR_DIV_ROUND_UP(MPI3MR_NUM_DEVRMCMD, 8);
19012d1d418eSSumit Saxena 	sc->devrem_bitmap = malloc(sc->devrem_bitmap_sz,
19022d1d418eSSumit Saxena 	    M_MPI3MR, M_NOWAIT | M_ZERO);
19032d1d418eSSumit Saxena 	if (!sc->devrem_bitmap) {
19042d1d418eSSumit Saxena 		printf(IOCNAME "Cannot alloc memory for dev remove bitmap\n",
19052d1d418eSSumit Saxena 		    sc->name);
19062d1d418eSSumit Saxena 		goto out_failed;
19072d1d418eSSumit Saxena 	}
19082d1d418eSSumit Saxena 
19092d1d418eSSumit Saxena 	sc->evtack_cmds_bitmap_sz = MPI3MR_DIV_ROUND_UP(MPI3MR_NUM_EVTACKCMD, 8);
19102d1d418eSSumit Saxena 
19112d1d418eSSumit Saxena 	sc->evtack_cmds_bitmap = malloc(sc->evtack_cmds_bitmap_sz,
19122d1d418eSSumit Saxena 		M_MPI3MR, M_NOWAIT | M_ZERO);
19132d1d418eSSumit Saxena 	if (!sc->evtack_cmds_bitmap)
19142d1d418eSSumit Saxena 		goto out_failed;
19152d1d418eSSumit Saxena 
19162d1d418eSSumit Saxena 	if (mpi3mr_reply_dma_alloc(sc)) {
19172d1d418eSSumit Saxena 		printf(IOCNAME "func:%s line:%d DMA memory allocation failed\n",
19182d1d418eSSumit Saxena 		    sc->name, __func__, __LINE__);
19192d1d418eSSumit Saxena 		goto out_failed;
19202d1d418eSSumit Saxena 	}
19212d1d418eSSumit Saxena 
19222d1d418eSSumit Saxena post_reply_sbuf:
19232d1d418eSSumit Saxena 	mpi3mr_setup_reply_free_queues(sc);
19242d1d418eSSumit Saxena 	return retval;
19252d1d418eSSumit Saxena out_failed:
19262d1d418eSSumit Saxena 	mpi3mr_cleanup_interrupts(sc);
19272d1d418eSSumit Saxena 	mpi3mr_free_mem(sc);
19282d1d418eSSumit Saxena 	retval = -1;
19292d1d418eSSumit Saxena 	return retval;
19302d1d418eSSumit Saxena }
19312d1d418eSSumit Saxena 
19322d1d418eSSumit Saxena static void
19332d1d418eSSumit Saxena mpi3mr_print_fw_pkg_ver(struct mpi3mr_softc *sc)
19342d1d418eSSumit Saxena {
19352d1d418eSSumit Saxena 	int retval = 0;
19362d1d418eSSumit Saxena 	void *fw_pkg_ver = NULL;
19372d1d418eSSumit Saxena 	bus_dma_tag_t fw_pkg_ver_tag;
19382d1d418eSSumit Saxena 	bus_dmamap_t fw_pkg_ver_map;
19392d1d418eSSumit Saxena 	bus_addr_t fw_pkg_ver_dma;
19402d1d418eSSumit Saxena 	Mpi3CIUploadRequest_t ci_upload;
19412d1d418eSSumit Saxena 	Mpi3ComponentImageHeader_t *ci_header;
19422d1d418eSSumit Saxena 	U32 fw_pkg_ver_len = sizeof(*ci_header);
19432d1d418eSSumit Saxena 	U8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
19442d1d418eSSumit Saxena 
19452d1d418eSSumit Saxena 	if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,  /* parent */
19462d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
19472d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
19482d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
19492d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
19502d1d418eSSumit Saxena 				fw_pkg_ver_len,		/* maxsize */
19512d1d418eSSumit Saxena 				1,			/* nsegments */
19522d1d418eSSumit Saxena 				fw_pkg_ver_len,		/* maxsegsize */
19532d1d418eSSumit Saxena 				0,			/* flags */
19542d1d418eSSumit Saxena 				NULL, NULL,		/* lockfunc, lockarg */
19552d1d418eSSumit Saxena 				&fw_pkg_ver_tag)) {
19562d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate fw package version request DMA tag\n");
19572d1d418eSSumit Saxena 		return;
19582d1d418eSSumit Saxena 	}
19592d1d418eSSumit Saxena 
19602d1d418eSSumit Saxena 	if (bus_dmamem_alloc(fw_pkg_ver_tag, (void **)&fw_pkg_ver, BUS_DMA_NOWAIT, &fw_pkg_ver_map)) {
19612d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d fw package version DMA mem alloc failed\n",
19622d1d418eSSumit Saxena 			      __func__, __LINE__);
19632d1d418eSSumit Saxena 		return;
19642d1d418eSSumit Saxena 	}
19652d1d418eSSumit Saxena 
19662d1d418eSSumit Saxena 	bzero(fw_pkg_ver, fw_pkg_ver_len);
19672d1d418eSSumit Saxena 
19682d1d418eSSumit 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);
19692d1d418eSSumit Saxena 
19702d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d fw package version phys addr= %#016jx size= %d\n",
19712d1d418eSSumit Saxena 		      __func__, __LINE__, (uintmax_t)fw_pkg_ver_dma, fw_pkg_ver_len);
19722d1d418eSSumit Saxena 
19732d1d418eSSumit Saxena 	if (!fw_pkg_ver) {
19742d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Memory alloc for fw package version failed\n");
19752d1d418eSSumit Saxena 		goto out;
19762d1d418eSSumit Saxena 	}
19772d1d418eSSumit Saxena 
19782d1d418eSSumit Saxena 	memset(&ci_upload, 0, sizeof(ci_upload));
19792d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
19802d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
19812d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,"Issue CI Header Upload: command is in use\n");
19822d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
19832d1d418eSSumit Saxena 		goto out;
19842d1d418eSSumit Saxena 	}
19852d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
19862d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
19872d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
19882d1d418eSSumit Saxena 	ci_upload.HostTag = htole16(MPI3MR_HOSTTAG_INITCMDS);
19892d1d418eSSumit Saxena 	ci_upload.Function = MPI3_FUNCTION_CI_UPLOAD;
19902d1d418eSSumit Saxena 	ci_upload.MsgFlags = MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY;
19912d1d418eSSumit Saxena 	ci_upload.ImageOffset = MPI3_IMAGE_HEADER_SIGNATURE0_OFFSET;
19922d1d418eSSumit Saxena 	ci_upload.SegmentSize = MPI3_IMAGE_HEADER_SIZE;
19932d1d418eSSumit Saxena 
19942d1d418eSSumit Saxena 	mpi3mr_add_sg_single(&ci_upload.SGL, sgl_flags, fw_pkg_ver_len,
19952d1d418eSSumit Saxena 	    fw_pkg_ver_dma);
19962d1d418eSSumit Saxena 
19972d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
19982d1d418eSSumit Saxena 	if ((retval = mpi3mr_submit_admin_cmd(sc, &ci_upload, sizeof(ci_upload)))) {
19992d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Issue CI Header Upload: Admin Post failed\n");
20002d1d418eSSumit Saxena 		goto out_unlock;
20012d1d418eSSumit Saxena 	}
20022d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
20032d1d418eSSumit Saxena 		(MPI3MR_INTADMCMD_TIMEOUT));
20042d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
20052d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Issue CI Header Upload: command timed out\n");
20062d1d418eSSumit Saxena 		sc->init_cmds.is_waiting = 0;
20072d1d418eSSumit Saxena 		if (!(sc->init_cmds.state & MPI3MR_CMD_RESET))
20082d1d418eSSumit Saxena 			mpi3mr_check_rh_fault_ioc(sc,
20092d1d418eSSumit Saxena 				MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT);
20102d1d418eSSumit Saxena 		goto out_unlock;
20112d1d418eSSumit Saxena 	}
20122d1d418eSSumit Saxena 	if ((GET_IOC_STATUS(sc->init_cmds.ioc_status)) != MPI3_IOCSTATUS_SUCCESS) {
20132d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
20142d1d418eSSumit Saxena 			      "Issue CI Header Upload: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n",
20152d1d418eSSumit Saxena 			      GET_IOC_STATUS(sc->init_cmds.ioc_status), sc->init_cmds.ioc_loginfo);
20162d1d418eSSumit Saxena 		goto out_unlock;
20172d1d418eSSumit Saxena 	}
20182d1d418eSSumit Saxena 
20192d1d418eSSumit Saxena 	ci_header = (Mpi3ComponentImageHeader_t *) fw_pkg_ver;
20202d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO,
20212d1d418eSSumit Saxena 		      "Issue CI Header Upload:EnvVariableOffset(0x%x) \
20222d1d418eSSumit Saxena 		      HeaderSize(0x%x) Signature1(0x%x)\n",
20232d1d418eSSumit Saxena 		      ci_header->EnvironmentVariableOffset,
20242d1d418eSSumit Saxena 		      ci_header->HeaderSize,
20252d1d418eSSumit Saxena 		      ci_header->Signature1);
20262d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "FW Package Version: %02d.%02d.%02d.%02d\n",
20272d1d418eSSumit Saxena 		      ci_header->ComponentImageVersion.GenMajor,
20282d1d418eSSumit Saxena 		      ci_header->ComponentImageVersion.GenMinor,
20292d1d418eSSumit Saxena 		      ci_header->ComponentImageVersion.PhaseMajor,
20302d1d418eSSumit Saxena 		      ci_header->ComponentImageVersion.PhaseMinor);
20312d1d418eSSumit Saxena out_unlock:
20322d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
20332d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
20342d1d418eSSumit Saxena 
20352d1d418eSSumit Saxena out:
20362d1d418eSSumit Saxena 	if (fw_pkg_ver_dma != 0)
20372d1d418eSSumit Saxena 		bus_dmamap_unload(fw_pkg_ver_tag, fw_pkg_ver_map);
20382d1d418eSSumit Saxena 	if (fw_pkg_ver)
20392d1d418eSSumit Saxena 		bus_dmamem_free(fw_pkg_ver_tag, fw_pkg_ver, fw_pkg_ver_map);
20402d1d418eSSumit Saxena 	if (fw_pkg_ver_tag)
20412d1d418eSSumit Saxena 		bus_dma_tag_destroy(fw_pkg_ver_tag);
20422d1d418eSSumit Saxena 
20432d1d418eSSumit Saxena }
20442d1d418eSSumit Saxena 
20452d1d418eSSumit Saxena /**
20462d1d418eSSumit Saxena  * mpi3mr_issue_iocinit - Send IOC Init
20472d1d418eSSumit Saxena  * @sc: Adapter instance reference
20482d1d418eSSumit Saxena  *
20492d1d418eSSumit Saxena  * Issue IOC Init MPI request through admin queue and wait for
20502d1d418eSSumit Saxena  * the completion of it or time out.
20512d1d418eSSumit Saxena  *
20522d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failures.
20532d1d418eSSumit Saxena  */
20542d1d418eSSumit Saxena static int mpi3mr_issue_iocinit(struct mpi3mr_softc *sc)
20552d1d418eSSumit Saxena {
20562d1d418eSSumit Saxena 	Mpi3IOCInitRequest_t iocinit_req;
20572d1d418eSSumit Saxena 	Mpi3DriverInfoLayout_t *drvr_info = NULL;
20582d1d418eSSumit Saxena 	bus_dma_tag_t drvr_info_tag;
20592d1d418eSSumit Saxena 	bus_dmamap_t drvr_info_map;
20602d1d418eSSumit Saxena 	bus_addr_t drvr_info_phys;
20612d1d418eSSumit Saxena 	U32 drvr_info_len = sizeof(*drvr_info);
20622d1d418eSSumit Saxena 	int retval = 0;
20632d1d418eSSumit Saxena 	struct timeval now;
20642d1d418eSSumit Saxena 	uint64_t time_in_msec;
20652d1d418eSSumit Saxena 
20662d1d418eSSumit Saxena 	if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,  /* parent */
20672d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
20682d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
20692d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
20702d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
20712d1d418eSSumit Saxena                                 drvr_info_len,		/* maxsize */
20722d1d418eSSumit Saxena                                 1,			/* nsegments */
20732d1d418eSSumit Saxena                                 drvr_info_len,		/* maxsegsize */
20742d1d418eSSumit Saxena                                 0,			/* flags */
20752d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
20762d1d418eSSumit Saxena                                 &drvr_info_tag)) {
20772d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
20782d1d418eSSumit Saxena 		return (ENOMEM);
20792d1d418eSSumit Saxena         }
20802d1d418eSSumit Saxena 
20812d1d418eSSumit Saxena 	if (bus_dmamem_alloc(drvr_info_tag, (void **)&drvr_info,
20822d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &drvr_info_map)) {
20832d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d Data  DMA mem alloc failed\n",
20842d1d418eSSumit Saxena 			__func__, __LINE__);
20852d1d418eSSumit Saxena 		return (ENOMEM);
20862d1d418eSSumit Saxena         }
20872d1d418eSSumit Saxena 
20882d1d418eSSumit Saxena 	bzero(drvr_info, drvr_info_len);
20892d1d418eSSumit Saxena         bus_dmamap_load(drvr_info_tag, drvr_info_map, drvr_info, drvr_info_len,
20902d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &drvr_info_phys, 0);
20912d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d IOCfacts drvr_info phys addr= %#016jx size= %d\n",
20922d1d418eSSumit Saxena 	    __func__, __LINE__, (uintmax_t)drvr_info_phys, drvr_info_len);
20932d1d418eSSumit Saxena 
20942d1d418eSSumit Saxena 	if (!drvr_info)
20952d1d418eSSumit Saxena 	{
20962d1d418eSSumit Saxena 		retval = -1;
20972d1d418eSSumit Saxena 		printf(IOCNAME "Memory alloc for Driver Info failed\n",
20982d1d418eSSumit Saxena 		    sc->name);
20992d1d418eSSumit Saxena 		goto out;
21002d1d418eSSumit Saxena 	}
21012d1d418eSSumit Saxena 	drvr_info->InformationLength = (drvr_info_len);
21022d1d418eSSumit Saxena 	strcpy(drvr_info->DriverSignature, "Broadcom");
21032d1d418eSSumit Saxena 	strcpy(drvr_info->OsName, "FreeBSD");
21042d1d418eSSumit Saxena 	strcpy(drvr_info->OsVersion, fmt_os_ver);
21052d1d418eSSumit Saxena 	strcpy(drvr_info->DriverName, MPI3MR_DRIVER_NAME);
21062d1d418eSSumit Saxena 	strcpy(drvr_info->DriverVersion, MPI3MR_DRIVER_VERSION);
21072d1d418eSSumit Saxena 	strcpy(drvr_info->DriverReleaseDate, MPI3MR_DRIVER_RELDATE);
21082d1d418eSSumit Saxena 	drvr_info->DriverCapabilities = 0;
21092d1d418eSSumit Saxena 	memcpy((U8 *)&sc->driver_info, (U8 *)drvr_info, sizeof(sc->driver_info));
21102d1d418eSSumit Saxena 
21112d1d418eSSumit Saxena 	memset(&iocinit_req, 0, sizeof(iocinit_req));
21122d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
21132d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
21142d1d418eSSumit Saxena 		retval = -1;
21152d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCInit: Init command is in use\n",
21162d1d418eSSumit Saxena 		    sc->name);
21172d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
21182d1d418eSSumit Saxena 		goto out;
21192d1d418eSSumit Saxena 	}
21202d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
21212d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
21222d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
21232d1d418eSSumit Saxena         iocinit_req.HostTag = MPI3MR_HOSTTAG_INITCMDS;
21242d1d418eSSumit Saxena         iocinit_req.Function = MPI3_FUNCTION_IOC_INIT;
21252d1d418eSSumit Saxena         iocinit_req.MPIVersion.Struct.Dev = MPI3_VERSION_DEV;
21262d1d418eSSumit Saxena         iocinit_req.MPIVersion.Struct.Unit = MPI3_VERSION_UNIT;
21272d1d418eSSumit Saxena         iocinit_req.MPIVersion.Struct.Major = MPI3_VERSION_MAJOR;
21282d1d418eSSumit Saxena         iocinit_req.MPIVersion.Struct.Minor = MPI3_VERSION_MINOR;
21292d1d418eSSumit Saxena         iocinit_req.WhoInit = MPI3_WHOINIT_HOST_DRIVER;
21302d1d418eSSumit Saxena         iocinit_req.ReplyFreeQueueDepth = sc->reply_free_q_sz;
21312d1d418eSSumit Saxena         iocinit_req.ReplyFreeQueueAddress =
21322d1d418eSSumit Saxena                 sc->reply_free_q_phys;
21332d1d418eSSumit Saxena         iocinit_req.SenseBufferLength = MPI3MR_SENSEBUF_SZ;
21342d1d418eSSumit Saxena         iocinit_req.SenseBufferFreeQueueDepth =
21352d1d418eSSumit Saxena                 sc->sense_buf_q_sz;
21362d1d418eSSumit Saxena         iocinit_req.SenseBufferFreeQueueAddress =
21372d1d418eSSumit Saxena                 sc->sense_buf_q_phys;
21382d1d418eSSumit Saxena         iocinit_req.DriverInformationAddress = drvr_info_phys;
21392d1d418eSSumit Saxena 
21402d1d418eSSumit Saxena 	getmicrotime(&now);
21412d1d418eSSumit Saxena 	time_in_msec = (now.tv_sec * 1000 + now.tv_usec/1000);
21422d1d418eSSumit Saxena 	iocinit_req.TimeStamp = htole64(time_in_msec);
21432d1d418eSSumit Saxena 
21442d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
21452d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &iocinit_req,
21462d1d418eSSumit Saxena 	    sizeof(iocinit_req));
21472d1d418eSSumit Saxena 
21482d1d418eSSumit Saxena 	if (retval) {
21492d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCInit: Admin Post failed\n",
21502d1d418eSSumit Saxena 		    sc->name);
21512d1d418eSSumit Saxena 		goto out_unlock;
21522d1d418eSSumit Saxena 	}
21532d1d418eSSumit Saxena 
21542d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
21552d1d418eSSumit Saxena 	    (MPI3MR_INTADMCMD_TIMEOUT));
21562d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
21572d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCInit: command timed out\n",
21582d1d418eSSumit Saxena 		    sc->name);
21592d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
21602d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_IOCINIT_TIMEOUT);
21612d1d418eSSumit Saxena 		sc->unrecoverable = 1;
21622d1d418eSSumit Saxena 		retval = -1;
21632d1d418eSSumit Saxena 		goto out_unlock;
21642d1d418eSSumit Saxena 	}
21652d1d418eSSumit Saxena 
21662d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
21672d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
21682d1d418eSSumit Saxena 		printf(IOCNAME "Issue IOCInit: Failed IOCStatus(0x%04x) "
21692d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
21702d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
21712d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
21722d1d418eSSumit Saxena 		retval = -1;
21732d1d418eSSumit Saxena 		goto out_unlock;
21742d1d418eSSumit Saxena 	}
21752d1d418eSSumit Saxena 
21762d1d418eSSumit Saxena out_unlock:
21772d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
21782d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
21792d1d418eSSumit Saxena 
21802d1d418eSSumit Saxena out:
21812d1d418eSSumit Saxena 	if (drvr_info_phys != 0)
21822d1d418eSSumit Saxena 		bus_dmamap_unload(drvr_info_tag, drvr_info_map);
21832d1d418eSSumit Saxena 	if (drvr_info != NULL)
21842d1d418eSSumit Saxena 		bus_dmamem_free(drvr_info_tag, drvr_info, drvr_info_map);
21852d1d418eSSumit Saxena 	if (drvr_info_tag != NULL)
21862d1d418eSSumit Saxena 		bus_dma_tag_destroy(drvr_info_tag);
21872d1d418eSSumit Saxena 	return retval;
21882d1d418eSSumit Saxena }
21892d1d418eSSumit Saxena 
21902d1d418eSSumit Saxena static void
21912d1d418eSSumit Saxena mpi3mr_display_ioc_info(struct mpi3mr_softc *sc)
21922d1d418eSSumit Saxena {
21932d1d418eSSumit Saxena         int i = 0;
21942d1d418eSSumit Saxena         char personality[16];
21952d1d418eSSumit Saxena         struct mpi3mr_compimg_ver *fwver = &sc->facts.fw_ver;
21962d1d418eSSumit Saxena 
21972d1d418eSSumit Saxena         switch (sc->facts.personality) {
21982d1d418eSSumit Saxena         case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA:
21992d1d418eSSumit Saxena                 strcpy(personality, "Enhanced HBA");
22002d1d418eSSumit Saxena                 break;
22012d1d418eSSumit Saxena         case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR:
22022d1d418eSSumit Saxena                 strcpy(personality, "RAID");
22032d1d418eSSumit Saxena                 break;
22042d1d418eSSumit Saxena         default:
22052d1d418eSSumit Saxena                 strcpy(personality, "Unknown");
22062d1d418eSSumit Saxena                 break;
22072d1d418eSSumit Saxena         }
22082d1d418eSSumit Saxena 
22092d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "Current Personality: %s\n", personality);
22102d1d418eSSumit Saxena 
22112d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "FW Version: %d.%d.%d.%d.%05d-%05d\n",
22122d1d418eSSumit Saxena 		      fwver->gen_major, fwver->gen_minor, fwver->ph_major,
22132d1d418eSSumit Saxena 		      fwver->ph_minor, fwver->cust_id, fwver->build_num);
22142d1d418eSSumit Saxena 
22152d1d418eSSumit Saxena         mpi3mr_dprint(sc, MPI3MR_INFO, "Protocol=(");
22162d1d418eSSumit Saxena 
22172d1d418eSSumit Saxena         if (sc->facts.protocol_flags &
22182d1d418eSSumit Saxena             MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR) {
22192d1d418eSSumit Saxena                 printf("Initiator");
22202d1d418eSSumit Saxena                 i++;
22212d1d418eSSumit Saxena         }
22222d1d418eSSumit Saxena 
22232d1d418eSSumit Saxena         if (sc->facts.protocol_flags &
22242d1d418eSSumit Saxena             MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET) {
22252d1d418eSSumit Saxena                 printf("%sTarget", i ? "," : "");
22262d1d418eSSumit Saxena                 i++;
22272d1d418eSSumit Saxena         }
22282d1d418eSSumit Saxena 
22292d1d418eSSumit Saxena         if (sc->facts.protocol_flags &
22302d1d418eSSumit Saxena             MPI3_IOCFACTS_PROTOCOL_NVME) {
22312d1d418eSSumit Saxena                 printf("%sNVMe attachment", i ? "," : "");
22322d1d418eSSumit Saxena                 i++;
22332d1d418eSSumit Saxena         }
22342d1d418eSSumit Saxena         i = 0;
22352d1d418eSSumit Saxena         printf("), ");
22362d1d418eSSumit Saxena         printf("Capabilities=(");
22372d1d418eSSumit Saxena 
22382d1d418eSSumit Saxena         if (sc->facts.ioc_capabilities &
22392d1d418eSSumit Saxena             MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE) {
22402d1d418eSSumit Saxena                 printf("RAID");
22412d1d418eSSumit Saxena                 i++;
22422d1d418eSSumit Saxena         }
22432d1d418eSSumit Saxena 
22442d1d418eSSumit Saxena         printf(")\n");
22452d1d418eSSumit Saxena }
22462d1d418eSSumit Saxena 
22472d1d418eSSumit Saxena /**
22482d1d418eSSumit Saxena  * mpi3mr_unmask_events - Unmask events in event mask bitmap
22492d1d418eSSumit Saxena  * @sc: Adapter instance reference
22502d1d418eSSumit Saxena  * @event: MPI event ID
22512d1d418eSSumit Saxena  *
22522d1d418eSSumit Saxena  * Un mask the specific event by resetting the event_mask
22532d1d418eSSumit Saxena  * bitmap.
22542d1d418eSSumit Saxena  *
22552d1d418eSSumit Saxena  * Return: None.
22562d1d418eSSumit Saxena  */
22572d1d418eSSumit Saxena static void mpi3mr_unmask_events(struct mpi3mr_softc *sc, U16 event)
22582d1d418eSSumit Saxena {
22592d1d418eSSumit Saxena 	U32 desired_event;
22602d1d418eSSumit Saxena 
22612d1d418eSSumit Saxena 	if (event >= 128)
22622d1d418eSSumit Saxena 		return;
22632d1d418eSSumit Saxena 
22642d1d418eSSumit Saxena 	desired_event = (1 << (event % 32));
22652d1d418eSSumit Saxena 
22662d1d418eSSumit Saxena 	if (event < 32)
22672d1d418eSSumit Saxena 		sc->event_masks[0] &= ~desired_event;
22682d1d418eSSumit Saxena 	else if (event < 64)
22692d1d418eSSumit Saxena 		sc->event_masks[1] &= ~desired_event;
22702d1d418eSSumit Saxena 	else if (event < 96)
22712d1d418eSSumit Saxena 		sc->event_masks[2] &= ~desired_event;
22722d1d418eSSumit Saxena 	else if (event < 128)
22732d1d418eSSumit Saxena 		sc->event_masks[3] &= ~desired_event;
22742d1d418eSSumit Saxena }
22752d1d418eSSumit Saxena 
22762d1d418eSSumit Saxena static void mpi3mr_set_events_mask(struct mpi3mr_softc *sc)
22772d1d418eSSumit Saxena {
22782d1d418eSSumit Saxena 	int i;
22792d1d418eSSumit Saxena 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
22802d1d418eSSumit Saxena 		sc->event_masks[i] = -1;
22812d1d418eSSumit Saxena 
22822d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_DEVICE_ADDED);
22832d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_DEVICE_INFO_CHANGED);
22842d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
22852d1d418eSSumit Saxena 
22862d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
22872d1d418eSSumit Saxena 
22882d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
22892d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_DISCOVERY);
22902d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
22912d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE);
22922d1d418eSSumit Saxena 
22932d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
22942d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_PCIE_ENUMERATION);
22952d1d418eSSumit Saxena 
22962d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_PREPARE_FOR_RESET);
22972d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_CABLE_MGMT);
22982d1d418eSSumit Saxena         mpi3mr_unmask_events(sc, MPI3_EVENT_ENERGY_PACK_CHANGE);
22992d1d418eSSumit Saxena }
23002d1d418eSSumit Saxena 
23012d1d418eSSumit Saxena /**
23022d1d418eSSumit Saxena  * mpi3mr_issue_event_notification - Send event notification
23032d1d418eSSumit Saxena  * @sc: Adapter instance reference
23042d1d418eSSumit Saxena  *
23052d1d418eSSumit Saxena  * Issue event notification MPI request through admin queue and
23062d1d418eSSumit Saxena  * wait for the completion of it or time out.
23072d1d418eSSumit Saxena  *
23082d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failures.
23092d1d418eSSumit Saxena  */
23102d1d418eSSumit Saxena int mpi3mr_issue_event_notification(struct mpi3mr_softc *sc)
23112d1d418eSSumit Saxena {
23122d1d418eSSumit Saxena 	Mpi3EventNotificationRequest_t evtnotify_req;
23132d1d418eSSumit Saxena 	int retval = 0;
23142d1d418eSSumit Saxena 	U8 i;
23152d1d418eSSumit Saxena 
23162d1d418eSSumit Saxena 	memset(&evtnotify_req, 0, sizeof(evtnotify_req));
23172d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
23182d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
23192d1d418eSSumit Saxena 		retval = -1;
23202d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtNotify: Init command is in use\n",
23212d1d418eSSumit Saxena 		    sc->name);
23222d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
23232d1d418eSSumit Saxena 		goto out;
23242d1d418eSSumit Saxena 	}
23252d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
23262d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
23272d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
23282d1d418eSSumit Saxena 	evtnotify_req.HostTag = (MPI3MR_HOSTTAG_INITCMDS);
23292d1d418eSSumit Saxena 	evtnotify_req.Function = MPI3_FUNCTION_EVENT_NOTIFICATION;
23302d1d418eSSumit Saxena 	for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
23312d1d418eSSumit Saxena 		evtnotify_req.EventMasks[i] =
23322d1d418eSSumit Saxena 		    (sc->event_masks[i]);
23332d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
23342d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &evtnotify_req,
23352d1d418eSSumit Saxena 	    sizeof(evtnotify_req));
23362d1d418eSSumit Saxena 	if (retval) {
23372d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtNotify: Admin Post failed\n",
23382d1d418eSSumit Saxena 		    sc->name);
23392d1d418eSSumit Saxena 		goto out_unlock;
23402d1d418eSSumit Saxena 	}
23412d1d418eSSumit Saxena 
23422d1d418eSSumit Saxena 	poll_for_command_completion(sc,
23432d1d418eSSumit Saxena 				    &sc->init_cmds,
23442d1d418eSSumit Saxena 				    (MPI3MR_INTADMCMD_TIMEOUT));
23452d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
23462d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtNotify: command timed out\n",
23472d1d418eSSumit Saxena 		    sc->name);
23482d1d418eSSumit Saxena 		mpi3mr_check_rh_fault_ioc(sc,
23492d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT);
23502d1d418eSSumit Saxena 		retval = -1;
23512d1d418eSSumit Saxena 		goto out_unlock;
23522d1d418eSSumit Saxena 	}
23532d1d418eSSumit Saxena 
23542d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
23552d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
23562d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtNotify: Failed IOCStatus(0x%04x) "
23572d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
23582d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
23592d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
23602d1d418eSSumit Saxena 		retval = -1;
23612d1d418eSSumit Saxena 		goto out_unlock;
23622d1d418eSSumit Saxena 	}
23632d1d418eSSumit Saxena 
23642d1d418eSSumit Saxena out_unlock:
23652d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
23662d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
23672d1d418eSSumit Saxena 
23682d1d418eSSumit Saxena out:
23692d1d418eSSumit Saxena 	return retval;
23702d1d418eSSumit Saxena }
23712d1d418eSSumit Saxena 
23722d1d418eSSumit Saxena int
23732d1d418eSSumit Saxena mpi3mr_register_events(struct mpi3mr_softc *sc)
23742d1d418eSSumit Saxena {
23752d1d418eSSumit Saxena 	int error;
23762d1d418eSSumit Saxena 
23772d1d418eSSumit Saxena 	mpi3mr_set_events_mask(sc);
23782d1d418eSSumit Saxena 
23792d1d418eSSumit Saxena 	error = mpi3mr_issue_event_notification(sc);
23802d1d418eSSumit Saxena 
23812d1d418eSSumit Saxena 	if (error) {
23822d1d418eSSumit Saxena 		printf(IOCNAME "Failed to issue event notification %d\n",
23832d1d418eSSumit Saxena 		    sc->name, error);
23842d1d418eSSumit Saxena 	}
23852d1d418eSSumit Saxena 
23862d1d418eSSumit Saxena 	return error;
23872d1d418eSSumit Saxena }
23882d1d418eSSumit Saxena 
23892d1d418eSSumit Saxena /**
23902d1d418eSSumit Saxena  * mpi3mr_process_event_ack - Process event acknowledgment
23912d1d418eSSumit Saxena  * @sc: Adapter instance reference
23922d1d418eSSumit Saxena  * @event: MPI3 event ID
23932d1d418eSSumit Saxena  * @event_ctx: Event context
23942d1d418eSSumit Saxena  *
23952d1d418eSSumit Saxena  * Send event acknowledgement through admin queue and wait for
23962d1d418eSSumit Saxena  * it to complete.
23972d1d418eSSumit Saxena  *
23982d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failures.
23992d1d418eSSumit Saxena  */
24002d1d418eSSumit Saxena int mpi3mr_process_event_ack(struct mpi3mr_softc *sc, U8 event,
24012d1d418eSSumit Saxena 	U32 event_ctx)
24022d1d418eSSumit Saxena {
24032d1d418eSSumit Saxena 	Mpi3EventAckRequest_t evtack_req;
24042d1d418eSSumit Saxena 	int retval = 0;
24052d1d418eSSumit Saxena 
24062d1d418eSSumit Saxena 	memset(&evtack_req, 0, sizeof(evtack_req));
24072d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
24082d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
24092d1d418eSSumit Saxena 		retval = -1;
24102d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtAck: Init command is in use\n",
24112d1d418eSSumit Saxena 		    sc->name);
24122d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
24132d1d418eSSumit Saxena 		goto out;
24142d1d418eSSumit Saxena 	}
24152d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
24162d1d418eSSumit Saxena 	sc->init_cmds.is_waiting = 1;
24172d1d418eSSumit Saxena 	sc->init_cmds.callback = NULL;
24182d1d418eSSumit Saxena 	evtack_req.HostTag = htole16(MPI3MR_HOSTTAG_INITCMDS);
24192d1d418eSSumit Saxena 	evtack_req.Function = MPI3_FUNCTION_EVENT_ACK;
24202d1d418eSSumit Saxena 	evtack_req.Event = event;
24212d1d418eSSumit Saxena 	evtack_req.EventContext = htole32(event_ctx);
24222d1d418eSSumit Saxena 
24232d1d418eSSumit Saxena 	init_completion(&sc->init_cmds.completion);
24242d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &evtack_req,
24252d1d418eSSumit Saxena 	    sizeof(evtack_req));
24262d1d418eSSumit Saxena 	if (retval) {
24272d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtAck: Admin Post failed\n",
24282d1d418eSSumit Saxena 		    sc->name);
24292d1d418eSSumit Saxena 		goto out_unlock;
24302d1d418eSSumit Saxena 	}
24312d1d418eSSumit Saxena 
24322d1d418eSSumit Saxena 	wait_for_completion_timeout(&sc->init_cmds.completion,
24332d1d418eSSumit Saxena 	    (MPI3MR_INTADMCMD_TIMEOUT));
24342d1d418eSSumit Saxena 	if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
24352d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtAck: command timed out\n",
24362d1d418eSSumit Saxena 		    sc->name);
24372d1d418eSSumit Saxena 		retval = -1;
24382d1d418eSSumit Saxena 		goto out_unlock;
24392d1d418eSSumit Saxena 	}
24402d1d418eSSumit Saxena 
24412d1d418eSSumit Saxena 	if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
24422d1d418eSSumit Saxena 	     != MPI3_IOCSTATUS_SUCCESS ) {
24432d1d418eSSumit Saxena 		printf(IOCNAME "Issue EvtAck: Failed IOCStatus(0x%04x) "
24442d1d418eSSumit Saxena 		    " Loginfo(0x%08x) \n" , sc->name,
24452d1d418eSSumit Saxena 		    (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
24462d1d418eSSumit Saxena 		    sc->init_cmds.ioc_loginfo);
24472d1d418eSSumit Saxena 		retval = -1;
24482d1d418eSSumit Saxena 		goto out_unlock;
24492d1d418eSSumit Saxena 	}
24502d1d418eSSumit Saxena 
24512d1d418eSSumit Saxena out_unlock:
24522d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
24532d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
24542d1d418eSSumit Saxena 
24552d1d418eSSumit Saxena out:
24562d1d418eSSumit Saxena 	return retval;
24572d1d418eSSumit Saxena }
24582d1d418eSSumit Saxena 
24592d1d418eSSumit Saxena 
24602d1d418eSSumit Saxena static int mpi3mr_alloc_chain_bufs(struct mpi3mr_softc *sc)
24612d1d418eSSumit Saxena {
24622d1d418eSSumit Saxena 	int retval = 0;
24632d1d418eSSumit Saxena 	U32 sz, i;
24642d1d418eSSumit Saxena 	U16 num_chains;
24652d1d418eSSumit Saxena 
24662d1d418eSSumit Saxena 	num_chains = sc->max_host_ios;
24672d1d418eSSumit Saxena 
24682d1d418eSSumit Saxena 	sc->chain_buf_count = num_chains;
24692d1d418eSSumit Saxena 	sz = sizeof(struct mpi3mr_chain) * num_chains;
24702d1d418eSSumit Saxena 
24712d1d418eSSumit Saxena 	sc->chain_sgl_list = malloc(sz, M_MPI3MR, M_NOWAIT | M_ZERO);
24722d1d418eSSumit Saxena 
24732d1d418eSSumit Saxena 	if (!sc->chain_sgl_list) {
24742d1d418eSSumit Saxena 		printf(IOCNAME "Cannot allocate memory for chain SGL list\n",
24752d1d418eSSumit Saxena 		    sc->name);
24762d1d418eSSumit Saxena 		retval = -1;
24772d1d418eSSumit Saxena 		goto out_failed;
24782d1d418eSSumit Saxena 	}
24792d1d418eSSumit Saxena 
24802d1d418eSSumit Saxena 	sz = MPI3MR_CHAINSGE_SIZE;
24812d1d418eSSumit Saxena 
24822d1d418eSSumit Saxena         if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,  /* parent */
24832d1d418eSSumit Saxena 				4096, 0,		/* algnmnt, boundary */
24842d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
24852d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
24862d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
24872d1d418eSSumit Saxena                                 sz,			/* maxsize */
24882d1d418eSSumit Saxena                                 1,			/* nsegments */
24892d1d418eSSumit Saxena                                 sz,			/* maxsegsize */
24902d1d418eSSumit Saxena                                 0,			/* flags */
24912d1d418eSSumit Saxena                                 NULL, NULL,		/* lockfunc, lockarg */
24922d1d418eSSumit Saxena                                 &sc->chain_sgl_list_tag)) {
24932d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Chain buffer DMA tag\n");
24942d1d418eSSumit Saxena 		return (ENOMEM);
24952d1d418eSSumit Saxena         }
24962d1d418eSSumit Saxena 
24972d1d418eSSumit Saxena 	for (i = 0; i < num_chains; i++) {
24982d1d418eSSumit Saxena 		if (bus_dmamem_alloc(sc->chain_sgl_list_tag, (void **)&sc->chain_sgl_list[i].buf,
24992d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &sc->chain_sgl_list[i].buf_dmamap)) {
25002d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d  DMA mem alloc failed\n",
25012d1d418eSSumit Saxena 				__func__, __LINE__);
25022d1d418eSSumit Saxena 			return (ENOMEM);
25032d1d418eSSumit Saxena 		}
25042d1d418eSSumit Saxena 
25052d1d418eSSumit Saxena 		bzero(sc->chain_sgl_list[i].buf, sz);
25062d1d418eSSumit Saxena 		bus_dmamap_load(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf_dmamap, sc->chain_sgl_list[i].buf, sz,
25072d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &sc->chain_sgl_list[i].buf_phys, 0);
25082d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d phys addr= %#016jx size= %d\n",
25092d1d418eSSumit Saxena 		    __func__, __LINE__, (uintmax_t)sc->chain_sgl_list[i].buf_phys, sz);
25102d1d418eSSumit Saxena 	}
25112d1d418eSSumit Saxena 
25122d1d418eSSumit Saxena 	sc->chain_bitmap_sz = MPI3MR_DIV_ROUND_UP(num_chains, 8);
25132d1d418eSSumit Saxena 
25142d1d418eSSumit Saxena 	sc->chain_bitmap = malloc(sc->chain_bitmap_sz, M_MPI3MR, M_NOWAIT | M_ZERO);
25152d1d418eSSumit Saxena 	if (!sc->chain_bitmap) {
25162d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "Cannot alloc memory for chain bitmap\n");
25172d1d418eSSumit Saxena 		retval = -1;
25182d1d418eSSumit Saxena 		goto out_failed;
25192d1d418eSSumit Saxena 	}
25202d1d418eSSumit Saxena 	return retval;
25212d1d418eSSumit Saxena 
25222d1d418eSSumit Saxena out_failed:
25232d1d418eSSumit Saxena 	for (i = 0; i < num_chains; i++) {
25242d1d418eSSumit Saxena 		if (sc->chain_sgl_list[i].buf_phys != 0)
25252d1d418eSSumit Saxena 			bus_dmamap_unload(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf_dmamap);
25262d1d418eSSumit Saxena 		if (sc->chain_sgl_list[i].buf != NULL)
25272d1d418eSSumit Saxena 			bus_dmamem_free(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf, sc->chain_sgl_list[i].buf_dmamap);
25282d1d418eSSumit Saxena 	}
25292d1d418eSSumit Saxena 	if (sc->chain_sgl_list_tag != NULL)
25302d1d418eSSumit Saxena 		bus_dma_tag_destroy(sc->chain_sgl_list_tag);
25312d1d418eSSumit Saxena 	return retval;
25322d1d418eSSumit Saxena }
25332d1d418eSSumit Saxena 
25342d1d418eSSumit Saxena static int mpi3mr_pel_alloc(struct mpi3mr_softc *sc)
25352d1d418eSSumit Saxena {
25362d1d418eSSumit Saxena 	int retval = 0;
25372d1d418eSSumit Saxena 
25382d1d418eSSumit Saxena 	if (!sc->pel_cmds.reply) {
25392d1d418eSSumit Saxena 		sc->pel_cmds.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO);
25402d1d418eSSumit Saxena 		if (!sc->pel_cmds.reply) {
25412d1d418eSSumit Saxena 			printf(IOCNAME "Cannot allocate memory for pel_cmds.reply\n",
25422d1d418eSSumit Saxena 			    sc->name);
25432d1d418eSSumit Saxena 			goto out_failed;
25442d1d418eSSumit Saxena 		}
25452d1d418eSSumit Saxena 	}
25462d1d418eSSumit Saxena 
25472d1d418eSSumit Saxena 	if (!sc->pel_abort_cmd.reply) {
25482d1d418eSSumit Saxena 		sc->pel_abort_cmd.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO);
25492d1d418eSSumit Saxena 		if (!sc->pel_abort_cmd.reply) {
25502d1d418eSSumit Saxena 			printf(IOCNAME "Cannot allocate memory for pel_abort_cmd.reply\n",
25512d1d418eSSumit Saxena 			    sc->name);
25522d1d418eSSumit Saxena 			goto out_failed;
25532d1d418eSSumit Saxena 		}
25542d1d418eSSumit Saxena 	}
25552d1d418eSSumit Saxena 
25562d1d418eSSumit Saxena 	if (!sc->pel_seq_number) {
25572d1d418eSSumit Saxena 		sc->pel_seq_number_sz = sizeof(Mpi3PELSeq_t);
25582d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,   /* parent */
25592d1d418eSSumit Saxena 				 4, 0,                           /* alignment, boundary */
25602d1d418eSSumit Saxena 				 BUS_SPACE_MAXADDR_32BIT,        /* lowaddr */
25612d1d418eSSumit Saxena 				 BUS_SPACE_MAXADDR,              /* highaddr */
25622d1d418eSSumit Saxena 				 NULL, NULL,                     /* filter, filterarg */
25632d1d418eSSumit Saxena 				 sc->pel_seq_number_sz,		 /* maxsize */
25642d1d418eSSumit Saxena 				 1,                              /* nsegments */
25652d1d418eSSumit Saxena 				 sc->pel_seq_number_sz,          /* maxsegsize */
25662d1d418eSSumit Saxena 				 0,                              /* flags */
25672d1d418eSSumit Saxena 				 NULL, NULL,                     /* lockfunc, lockarg */
25682d1d418eSSumit Saxena 				 &sc->pel_seq_num_dmatag)) {
25692d1d418eSSumit Saxena 			 mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot create PEL seq number dma memory tag\n");
25702d1d418eSSumit Saxena 			 retval = -ENOMEM;
25712d1d418eSSumit Saxena 			 goto out_failed;
25722d1d418eSSumit Saxena 		}
25732d1d418eSSumit Saxena 
25742d1d418eSSumit Saxena 		if (bus_dmamem_alloc(sc->pel_seq_num_dmatag, (void **)&sc->pel_seq_number,
25752d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &sc->pel_seq_num_dmamap)) {
25762d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate PEL seq number kernel buffer dma memory\n");
25772d1d418eSSumit Saxena 			retval = -ENOMEM;
25782d1d418eSSumit Saxena 			goto out_failed;
25792d1d418eSSumit Saxena 		}
25802d1d418eSSumit Saxena 
25812d1d418eSSumit Saxena 		bzero(sc->pel_seq_number, sc->pel_seq_number_sz);
25822d1d418eSSumit Saxena 
25832d1d418eSSumit Saxena 		bus_dmamap_load(sc->pel_seq_num_dmatag, sc->pel_seq_num_dmamap, sc->pel_seq_number,
25842d1d418eSSumit Saxena 		    sc->pel_seq_number_sz, mpi3mr_memaddr_cb, &sc->pel_seq_number_dma, 0);
25852d1d418eSSumit Saxena 
25862d1d418eSSumit Saxena 		if (!sc->pel_seq_number) {
25872d1d418eSSumit Saxena 			printf(IOCNAME "%s:%d Cannot load PEL seq number dma memory for size: %d\n", sc->name,
25882d1d418eSSumit Saxena 				__func__, __LINE__, sc->pel_seq_number_sz);
25892d1d418eSSumit Saxena 			retval = -ENOMEM;
25902d1d418eSSumit Saxena 			goto out_failed;
25912d1d418eSSumit Saxena 		}
25922d1d418eSSumit Saxena 	}
25932d1d418eSSumit Saxena 
25942d1d418eSSumit Saxena out_failed:
25952d1d418eSSumit Saxena 	return retval;
25962d1d418eSSumit Saxena }
25972d1d418eSSumit Saxena 
25982d1d418eSSumit Saxena /**
25992d1d418eSSumit Saxena  * mpi3mr_validate_fw_update - validate IOCFacts post adapter reset
26002d1d418eSSumit Saxena  * @sc: Adapter instance reference
26012d1d418eSSumit Saxena  *
26022d1d418eSSumit Saxena  * Return zero if the new IOCFacts is compatible with previous values
26032d1d418eSSumit Saxena  * else return appropriate error
26042d1d418eSSumit Saxena  */
26052d1d418eSSumit Saxena static int
26062d1d418eSSumit Saxena mpi3mr_validate_fw_update(struct mpi3mr_softc *sc)
26072d1d418eSSumit Saxena {
26082d1d418eSSumit Saxena 	U16 dev_handle_bitmap_sz;
26092d1d418eSSumit Saxena 	U8 *removepend_bitmap;
26102d1d418eSSumit Saxena 
26112d1d418eSSumit Saxena 	if (sc->facts.reply_sz > sc->reply_sz) {
26122d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
26132d1d418eSSumit Saxena 		    "Cannot increase reply size from %d to %d\n",
26142d1d418eSSumit Saxena 		    sc->reply_sz, sc->reply_sz);
26152d1d418eSSumit Saxena 		return -EPERM;
26162d1d418eSSumit Saxena 	}
26172d1d418eSSumit Saxena 
26182d1d418eSSumit Saxena 	if (sc->num_io_throttle_group != sc->facts.max_io_throttle_group) {
26192d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
26202d1d418eSSumit Saxena 		    "max io throttle group doesn't match old(%d), new(%d)\n",
26212d1d418eSSumit Saxena 		    sc->num_io_throttle_group,
26222d1d418eSSumit Saxena 		    sc->facts.max_io_throttle_group);
26232d1d418eSSumit Saxena 		return -EPERM;
26242d1d418eSSumit Saxena 	}
26252d1d418eSSumit Saxena 
26262d1d418eSSumit Saxena 	if (sc->facts.max_op_reply_q < sc->num_queues) {
26272d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
26282d1d418eSSumit Saxena 		    "Cannot reduce number of operational reply queues from %d to %d\n",
26292d1d418eSSumit Saxena 		    sc->num_queues,
26302d1d418eSSumit Saxena 		    sc->facts.max_op_reply_q);
26312d1d418eSSumit Saxena 		return -EPERM;
26322d1d418eSSumit Saxena 	}
26332d1d418eSSumit Saxena 
26342d1d418eSSumit Saxena 	if (sc->facts.max_op_req_q < sc->num_queues) {
26352d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
26362d1d418eSSumit Saxena 		    "Cannot reduce number of operational request queues from %d to %d\n",
26372d1d418eSSumit Saxena 		    sc->num_queues, sc->facts.max_op_req_q);
26382d1d418eSSumit Saxena 		return -EPERM;
26392d1d418eSSumit Saxena 	}
26402d1d418eSSumit Saxena 
26412d1d418eSSumit Saxena 	dev_handle_bitmap_sz = MPI3MR_DIV_ROUND_UP(sc->facts.max_devhandle, 8);
26422d1d418eSSumit Saxena 
26432d1d418eSSumit Saxena 	if (dev_handle_bitmap_sz > sc->dev_handle_bitmap_sz) {
26442d1d418eSSumit Saxena 		removepend_bitmap = realloc(sc->removepend_bitmap,
26452d1d418eSSumit Saxena 		    dev_handle_bitmap_sz, M_MPI3MR, M_NOWAIT);
26462d1d418eSSumit Saxena 
26472d1d418eSSumit Saxena 		if (!removepend_bitmap) {
26482d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
26492d1d418eSSumit Saxena 			    "failed to increase removepend_bitmap sz from: %d to %d\n",
26502d1d418eSSumit Saxena 			    sc->dev_handle_bitmap_sz, dev_handle_bitmap_sz);
26512d1d418eSSumit Saxena 			return -ENOMEM;
26522d1d418eSSumit Saxena 		}
26532d1d418eSSumit Saxena 
26542d1d418eSSumit Saxena 		memset(removepend_bitmap + sc->dev_handle_bitmap_sz, 0,
26552d1d418eSSumit Saxena 		    dev_handle_bitmap_sz - sc->dev_handle_bitmap_sz);
26562d1d418eSSumit Saxena 		sc->removepend_bitmap = removepend_bitmap;
26572d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
26582d1d418eSSumit Saxena 		    "increased dev_handle_bitmap_sz from %d to %d\n",
26592d1d418eSSumit Saxena 		    sc->dev_handle_bitmap_sz, dev_handle_bitmap_sz);
26602d1d418eSSumit Saxena 		sc->dev_handle_bitmap_sz = dev_handle_bitmap_sz;
26612d1d418eSSumit Saxena 	}
26622d1d418eSSumit Saxena 
26632d1d418eSSumit Saxena 	return 0;
26642d1d418eSSumit Saxena }
26652d1d418eSSumit Saxena 
26662d1d418eSSumit Saxena /*
26672d1d418eSSumit Saxena  * mpi3mr_initialize_ioc - Controller initialization
26682d1d418eSSumit Saxena  * @dev: pointer to device struct
26692d1d418eSSumit Saxena  *
26702d1d418eSSumit Saxena  * This function allocates the controller wide resources and brings
26712d1d418eSSumit Saxena  * the controller to operational state
26722d1d418eSSumit Saxena  *
26732d1d418eSSumit Saxena  * Return: 0 on success and proper error codes on failure
26742d1d418eSSumit Saxena  */
26752d1d418eSSumit Saxena int mpi3mr_initialize_ioc(struct mpi3mr_softc *sc, U8 init_type)
26762d1d418eSSumit Saxena {
26772d1d418eSSumit Saxena 	int retval = 0;
26782d1d418eSSumit Saxena 	enum mpi3mr_iocstate ioc_state;
26792d1d418eSSumit Saxena 	U64 ioc_info;
26802d1d418eSSumit Saxena 	U32 ioc_status, ioc_control, i, timeout;
26812d1d418eSSumit Saxena 	Mpi3IOCFactsData_t facts_data;
26822d1d418eSSumit Saxena 	char str[32];
26832d1d418eSSumit Saxena 	U32 size;
26842d1d418eSSumit Saxena 
26852d1d418eSSumit Saxena 	sc->cpu_count = mp_ncpus;
26862d1d418eSSumit Saxena 
26872d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
26882d1d418eSSumit Saxena 	ioc_control = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
26892d1d418eSSumit Saxena 	ioc_info = mpi3mr_regread64(sc, MPI3_SYSIF_IOC_INFO_LOW_OFFSET);
26902d1d418eSSumit Saxena 
26912d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "SOD ioc_status: 0x%x ioc_control: 0x%x "
26922d1d418eSSumit Saxena 	    "ioc_info: 0x%lx\n", ioc_status, ioc_control, ioc_info);
26932d1d418eSSumit Saxena 
26942d1d418eSSumit Saxena         /*The timeout value is in 2sec unit, changing it to seconds*/
26952d1d418eSSumit Saxena 	sc->ready_timeout =
26962d1d418eSSumit Saxena                 ((ioc_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
26972d1d418eSSumit Saxena                     MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
26982d1d418eSSumit Saxena 
26992d1d418eSSumit Saxena 	ioc_state = mpi3mr_get_iocstate(sc);
27002d1d418eSSumit Saxena 
27012d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "IOC state: %s   IOC ready timeout: %d\n",
27022d1d418eSSumit Saxena 	    mpi3mr_iocstate_name(ioc_state), sc->ready_timeout);
27032d1d418eSSumit Saxena 
27042d1d418eSSumit Saxena 	if (ioc_state == MRIOC_STATE_BECOMING_READY ||
27052d1d418eSSumit Saxena 	    ioc_state == MRIOC_STATE_RESET_REQUESTED) {
27062d1d418eSSumit Saxena 		timeout = sc->ready_timeout * 10;
27072d1d418eSSumit Saxena 		do {
27082d1d418eSSumit Saxena 			DELAY(1000 * 100);
27092d1d418eSSumit Saxena 		} while (--timeout);
27102d1d418eSSumit Saxena 
27112d1d418eSSumit Saxena 		ioc_state = mpi3mr_get_iocstate(sc);
27122d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
27132d1d418eSSumit Saxena 			"IOC in %s state after waiting for reset time\n",
27142d1d418eSSumit Saxena 			mpi3mr_iocstate_name(ioc_state));
27152d1d418eSSumit Saxena 	}
27162d1d418eSSumit Saxena 
27172d1d418eSSumit Saxena 	if (ioc_state == MRIOC_STATE_READY) {
27182d1d418eSSumit Saxena                 retval = mpi3mr_mur_ioc(sc, MPI3MR_RESET_FROM_BRINGUP);
27192d1d418eSSumit Saxena                 if (retval) {
27202d1d418eSSumit Saxena                         mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to MU reset IOC, error 0x%x\n",
27212d1d418eSSumit Saxena                                 retval);
27222d1d418eSSumit Saxena                 }
27232d1d418eSSumit Saxena                 ioc_state = mpi3mr_get_iocstate(sc);
27242d1d418eSSumit Saxena         }
27252d1d418eSSumit Saxena 
27262d1d418eSSumit Saxena         if (ioc_state != MRIOC_STATE_RESET) {
27272d1d418eSSumit Saxena                 mpi3mr_print_fault_info(sc);
27282d1d418eSSumit Saxena 		 mpi3mr_dprint(sc, MPI3MR_ERROR, "issuing soft reset to bring to reset state\n");
27292d1d418eSSumit Saxena                  retval = mpi3mr_issue_reset(sc,
27302d1d418eSSumit Saxena                      MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
27312d1d418eSSumit Saxena                      MPI3MR_RESET_FROM_BRINGUP);
27322d1d418eSSumit Saxena                 if (retval) {
27332d1d418eSSumit Saxena                         mpi3mr_dprint(sc, MPI3MR_ERROR,
27342d1d418eSSumit Saxena                             "%s :Failed to soft reset IOC, error 0x%d\n",
27352d1d418eSSumit Saxena                             __func__, retval);
27362d1d418eSSumit Saxena                         goto out_failed;
27372d1d418eSSumit Saxena                 }
27382d1d418eSSumit Saxena         }
27392d1d418eSSumit Saxena 
27402d1d418eSSumit Saxena 	ioc_state = mpi3mr_get_iocstate(sc);
27412d1d418eSSumit Saxena 
27422d1d418eSSumit Saxena         if (ioc_state != MRIOC_STATE_RESET) {
27432d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot bring IOC to reset state\n");
27442d1d418eSSumit Saxena 		goto out_failed;
27452d1d418eSSumit Saxena         }
27462d1d418eSSumit Saxena 
27472d1d418eSSumit Saxena 	retval = mpi3mr_setup_admin_qpair(sc);
27482d1d418eSSumit Saxena 	if (retval) {
27492d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to setup Admin queues, error 0x%x\n",
27502d1d418eSSumit Saxena 		    retval);
27512d1d418eSSumit Saxena 		goto out_failed;
27522d1d418eSSumit Saxena 	}
27532d1d418eSSumit Saxena 
27542d1d418eSSumit Saxena 	retval = mpi3mr_bring_ioc_ready(sc);
27552d1d418eSSumit Saxena 	if (retval) {
27562d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to bring IOC ready, error 0x%x\n",
27572d1d418eSSumit Saxena 		    retval);
27582d1d418eSSumit Saxena 		goto out_failed;
27592d1d418eSSumit Saxena 	}
27602d1d418eSSumit Saxena 
27612d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_INIT) {
27622d1d418eSSumit Saxena 		retval = mpi3mr_alloc_interrupts(sc, 1);
27632d1d418eSSumit Saxena 		if (retval) {
27642d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate interrupts, error 0x%x\n",
27652d1d418eSSumit Saxena 			    retval);
27662d1d418eSSumit Saxena 			goto out_failed;
27672d1d418eSSumit Saxena 		}
27682d1d418eSSumit Saxena 
27692d1d418eSSumit Saxena 		retval = mpi3mr_setup_irqs(sc);
27702d1d418eSSumit Saxena 		if (retval) {
27712d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to setup ISR, error 0x%x\n",
27722d1d418eSSumit Saxena 			    retval);
27732d1d418eSSumit Saxena 			goto out_failed;
27742d1d418eSSumit Saxena 		}
27752d1d418eSSumit Saxena 	}
27762d1d418eSSumit Saxena 
27772d1d418eSSumit Saxena 	mpi3mr_enable_interrupts(sc);
27782d1d418eSSumit Saxena 
27792d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_INIT) {
27802d1d418eSSumit Saxena 		mtx_init(&sc->mpi3mr_mtx, "SIM lock", NULL, MTX_DEF);
27812d1d418eSSumit Saxena 		mtx_init(&sc->io_lock, "IO lock", NULL, MTX_DEF);
27822d1d418eSSumit Saxena 		mtx_init(&sc->admin_req_lock, "Admin Request Queue lock", NULL, MTX_SPIN);
27832d1d418eSSumit Saxena 		mtx_init(&sc->reply_free_q_lock, "Reply free Queue lock", NULL, MTX_SPIN);
27842d1d418eSSumit Saxena 		mtx_init(&sc->sense_buf_q_lock, "Sense buffer Queue lock", NULL, MTX_SPIN);
27852d1d418eSSumit Saxena 		mtx_init(&sc->chain_buf_lock, "Chain buffer lock", NULL, MTX_SPIN);
27862d1d418eSSumit Saxena 		mtx_init(&sc->cmd_pool_lock, "Command pool lock", NULL, MTX_DEF);
27872d1d418eSSumit Saxena 		mtx_init(&sc->fwevt_lock, "Firmware Event lock", NULL, MTX_DEF);
27882d1d418eSSumit Saxena 		mtx_init(&sc->target_lock, "Target lock", NULL, MTX_SPIN);
27892d1d418eSSumit Saxena 		mtx_init(&sc->reset_mutex, "Reset lock", NULL, MTX_DEF);
27902d1d418eSSumit Saxena 
27912d1d418eSSumit Saxena 		mtx_init(&sc->init_cmds.completion.lock, "Init commands lock", NULL, MTX_DEF);
27922d1d418eSSumit Saxena 		sc->init_cmds.reply = NULL;
27932d1d418eSSumit Saxena 		sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
27942d1d418eSSumit Saxena 		sc->init_cmds.dev_handle = MPI3MR_INVALID_DEV_HANDLE;
27952d1d418eSSumit Saxena 		sc->init_cmds.host_tag = MPI3MR_HOSTTAG_INITCMDS;
27962d1d418eSSumit Saxena 
27972d1d418eSSumit Saxena 		mtx_init(&sc->ioctl_cmds.completion.lock, "IOCTL commands lock", NULL, MTX_DEF);
27982d1d418eSSumit Saxena 		sc->ioctl_cmds.reply = NULL;
27992d1d418eSSumit Saxena 		sc->ioctl_cmds.state = MPI3MR_CMD_NOTUSED;
28002d1d418eSSumit Saxena 		sc->ioctl_cmds.dev_handle = MPI3MR_INVALID_DEV_HANDLE;
28012d1d418eSSumit Saxena 		sc->ioctl_cmds.host_tag = MPI3MR_HOSTTAG_IOCTLCMDS;
28022d1d418eSSumit Saxena 
28032d1d418eSSumit Saxena 		mtx_init(&sc->pel_abort_cmd.completion.lock, "PEL Abort command lock", NULL, MTX_DEF);
28042d1d418eSSumit Saxena 		sc->pel_abort_cmd.reply = NULL;
28052d1d418eSSumit Saxena 		sc->pel_abort_cmd.state = MPI3MR_CMD_NOTUSED;
28062d1d418eSSumit Saxena 		sc->pel_abort_cmd.dev_handle = MPI3MR_INVALID_DEV_HANDLE;
28072d1d418eSSumit Saxena 		sc->pel_abort_cmd.host_tag = MPI3MR_HOSTTAG_PELABORT;
28082d1d418eSSumit Saxena 
28092d1d418eSSumit Saxena 		mtx_init(&sc->host_tm_cmds.completion.lock, "TM commands lock", NULL, MTX_DEF);
28102d1d418eSSumit Saxena 		sc->host_tm_cmds.reply = NULL;
28112d1d418eSSumit Saxena 		sc->host_tm_cmds.state = MPI3MR_CMD_NOTUSED;
28122d1d418eSSumit Saxena 		sc->host_tm_cmds.dev_handle = MPI3MR_INVALID_DEV_HANDLE;
28132d1d418eSSumit Saxena 		sc->host_tm_cmds.host_tag = MPI3MR_HOSTTAG_TMS;
28142d1d418eSSumit Saxena 
28152d1d418eSSumit Saxena 		TAILQ_INIT(&sc->cmd_list_head);
28162d1d418eSSumit Saxena 		TAILQ_INIT(&sc->event_list);
28172d1d418eSSumit Saxena 		TAILQ_INIT(&sc->delayed_rmhs_list);
28182d1d418eSSumit Saxena 		TAILQ_INIT(&sc->delayed_evtack_cmds_list);
28192d1d418eSSumit Saxena 
28202d1d418eSSumit Saxena 		for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
28212d1d418eSSumit Saxena 			snprintf(str, 32, "Dev REMHS commands lock[%d]", i);
28222d1d418eSSumit Saxena 			mtx_init(&sc->dev_rmhs_cmds[i].completion.lock, str, NULL, MTX_DEF);
28232d1d418eSSumit Saxena 			sc->dev_rmhs_cmds[i].reply = NULL;
28242d1d418eSSumit Saxena 			sc->dev_rmhs_cmds[i].state = MPI3MR_CMD_NOTUSED;
28252d1d418eSSumit Saxena 			sc->dev_rmhs_cmds[i].dev_handle = MPI3MR_INVALID_DEV_HANDLE;
28262d1d418eSSumit Saxena 			sc->dev_rmhs_cmds[i].host_tag = MPI3MR_HOSTTAG_DEVRMCMD_MIN
28272d1d418eSSumit Saxena 							    + i;
28282d1d418eSSumit Saxena 		}
28292d1d418eSSumit Saxena 	}
28302d1d418eSSumit Saxena 
28312d1d418eSSumit Saxena 	retval = mpi3mr_issue_iocfacts(sc, &facts_data);
28322d1d418eSSumit Saxena 	if (retval) {
28332d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to Issue IOC Facts, retval: 0x%x\n",
28342d1d418eSSumit Saxena 		    retval);
28352d1d418eSSumit Saxena 		goto out_failed;
28362d1d418eSSumit Saxena 	}
28372d1d418eSSumit Saxena 
28382d1d418eSSumit Saxena 	retval = mpi3mr_process_factsdata(sc, &facts_data);
28392d1d418eSSumit Saxena 	if (retval) {
28402d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "IOC Facts data processing failedi, retval: 0x%x\n",
28412d1d418eSSumit Saxena 		    retval);
28422d1d418eSSumit Saxena 		goto out_failed;
28432d1d418eSSumit Saxena 	}
28442d1d418eSSumit Saxena 
28452d1d418eSSumit Saxena 	sc->num_io_throttle_group = sc->facts.max_io_throttle_group;
28462d1d418eSSumit Saxena 	mpi3mr_atomic_set(&sc->pend_large_data_sz, 0);
28472d1d418eSSumit Saxena 
28482d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_RESET) {
28492d1d418eSSumit Saxena 		retval = mpi3mr_validate_fw_update(sc);
28502d1d418eSSumit Saxena 		if (retval)
28512d1d418eSSumit Saxena 			goto out_failed;
28522d1d418eSSumit Saxena 	} else {
28532d1d418eSSumit Saxena 		sc->reply_sz = sc->facts.reply_sz;
28542d1d418eSSumit Saxena 	}
28552d1d418eSSumit Saxena 
28562d1d418eSSumit Saxena 
28572d1d418eSSumit Saxena 	mpi3mr_display_ioc_info(sc);
28582d1d418eSSumit Saxena 
28592d1d418eSSumit Saxena 	retval = mpi3mr_reply_alloc(sc);
28602d1d418eSSumit Saxena 	if (retval) {
28612d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocated reply and sense buffers, retval: 0x%x\n",
28622d1d418eSSumit Saxena 		    retval);
28632d1d418eSSumit Saxena 		goto out_failed;
28642d1d418eSSumit Saxena 	}
28652d1d418eSSumit Saxena 
28662d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_INIT) {
28672d1d418eSSumit Saxena 		retval = mpi3mr_alloc_chain_bufs(sc);
28682d1d418eSSumit Saxena 		if (retval) {
28692d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocated chain buffers, retval: 0x%x\n",
28702d1d418eSSumit Saxena 			    retval);
28712d1d418eSSumit Saxena 			goto out_failed;
28722d1d418eSSumit Saxena 		}
28732d1d418eSSumit Saxena 	}
28742d1d418eSSumit Saxena 
28752d1d418eSSumit Saxena 	retval = mpi3mr_issue_iocinit(sc);
28762d1d418eSSumit Saxena 	if (retval) {
28772d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to Issue IOC Init, retval: 0x%x\n",
28782d1d418eSSumit Saxena 		    retval);
28792d1d418eSSumit Saxena 		goto out_failed;
28802d1d418eSSumit Saxena 	}
28812d1d418eSSumit Saxena 
28822d1d418eSSumit Saxena 	mpi3mr_print_fw_pkg_ver(sc);
28832d1d418eSSumit Saxena 
28842d1d418eSSumit Saxena 	sc->reply_free_q_host_index = sc->num_reply_bufs;
28852d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_REPLY_FREE_HOST_INDEX_OFFSET,
28862d1d418eSSumit Saxena 		sc->reply_free_q_host_index);
28872d1d418eSSumit Saxena 
28882d1d418eSSumit Saxena 	sc->sense_buf_q_host_index = sc->num_sense_bufs;
28892d1d418eSSumit Saxena 
28902d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_SENSE_BUF_FREE_HOST_INDEX_OFFSET,
28912d1d418eSSumit Saxena 		sc->sense_buf_q_host_index);
28922d1d418eSSumit Saxena 
28932d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_INIT) {
28942d1d418eSSumit Saxena 		retval = mpi3mr_alloc_interrupts(sc, 0);
28952d1d418eSSumit Saxena 		if (retval) {
28962d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate interrupts, retval: 0x%x\n",
28972d1d418eSSumit Saxena 			    retval);
28982d1d418eSSumit Saxena 			goto out_failed;
28992d1d418eSSumit Saxena 		}
29002d1d418eSSumit Saxena 
29012d1d418eSSumit Saxena 		retval = mpi3mr_setup_irqs(sc);
29022d1d418eSSumit Saxena 		if (retval) {
29032d1d418eSSumit Saxena 			printf(IOCNAME "Failed to setup ISR, error: 0x%x\n",
29042d1d418eSSumit Saxena 			    sc->name, retval);
29052d1d418eSSumit Saxena 			goto out_failed;
29062d1d418eSSumit Saxena 		}
29072d1d418eSSumit Saxena 
29082d1d418eSSumit Saxena 		mpi3mr_enable_interrupts(sc);
29092d1d418eSSumit Saxena 
29102d1d418eSSumit Saxena 	} else
29112d1d418eSSumit Saxena 		mpi3mr_enable_interrupts(sc);
29122d1d418eSSumit Saxena 
29132d1d418eSSumit Saxena 	retval = mpi3mr_create_op_queues(sc);
29142d1d418eSSumit Saxena 
29152d1d418eSSumit Saxena 	if (retval) {
29162d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to create operational queues, error: %d\n",
29172d1d418eSSumit Saxena 		    retval);
29182d1d418eSSumit Saxena 		goto out_failed;
29192d1d418eSSumit Saxena 	}
29202d1d418eSSumit Saxena 
29212d1d418eSSumit Saxena 	if (!sc->throttle_groups && sc->num_io_throttle_group) {
29222d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "allocating memory for throttle groups\n");
29232d1d418eSSumit Saxena 		size = sizeof(struct mpi3mr_throttle_group_info);
29242d1d418eSSumit Saxena 		sc->throttle_groups = (struct mpi3mr_throttle_group_info *)
29252d1d418eSSumit Saxena 					  malloc(sc->num_io_throttle_group *
29262d1d418eSSumit Saxena 					      size, M_MPI3MR, M_NOWAIT | M_ZERO);
29272d1d418eSSumit Saxena 		if (!sc->throttle_groups)
29282d1d418eSSumit Saxena 			goto out_failed;
29292d1d418eSSumit Saxena 	}
29302d1d418eSSumit Saxena 
29312d1d418eSSumit Saxena 	if (init_type == MPI3MR_INIT_TYPE_RESET) {
29322d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "Re-register events\n");
29332d1d418eSSumit Saxena 		retval = mpi3mr_register_events(sc);
29342d1d418eSSumit Saxena 		if (retval) {
29352d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO, "Failed to re-register events, retval: 0x%x\n",
29362d1d418eSSumit Saxena 			    retval);
29372d1d418eSSumit Saxena 			goto out_failed;
29382d1d418eSSumit Saxena 		}
29392d1d418eSSumit Saxena 
29402d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "Issuing Port Enable\n");
29412d1d418eSSumit Saxena 		retval = mpi3mr_issue_port_enable(sc, 0);
29422d1d418eSSumit Saxena 		if (retval) {
29432d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO, "Failed to issue port enable, retval: 0x%x\n",
29442d1d418eSSumit Saxena 			    retval);
29452d1d418eSSumit Saxena 			goto out_failed;
29462d1d418eSSumit Saxena 		}
29472d1d418eSSumit Saxena 	}
29482d1d418eSSumit Saxena 	retval = mpi3mr_pel_alloc(sc);
29492d1d418eSSumit Saxena 	if (retval) {
29502d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate memory for PEL, retval: 0x%x\n",
29512d1d418eSSumit Saxena 		    retval);
29522d1d418eSSumit Saxena 		goto out_failed;
29532d1d418eSSumit Saxena 	}
29542d1d418eSSumit Saxena 
29552d1d418eSSumit Saxena 	return retval;
29562d1d418eSSumit Saxena 
29572d1d418eSSumit Saxena out_failed:
29582d1d418eSSumit Saxena 	retval = -1;
29592d1d418eSSumit Saxena 	return retval;
29602d1d418eSSumit Saxena }
29612d1d418eSSumit Saxena 
29622d1d418eSSumit Saxena static void mpi3mr_port_enable_complete(struct mpi3mr_softc *sc,
29632d1d418eSSumit Saxena     struct mpi3mr_drvr_cmd *drvrcmd)
29642d1d418eSSumit Saxena {
29652d1d418eSSumit Saxena 	drvrcmd->state = MPI3MR_CMD_NOTUSED;
29662d1d418eSSumit Saxena 	drvrcmd->callback = NULL;
29672d1d418eSSumit Saxena 	printf(IOCNAME "Completing Port Enable Request\n", sc->name);
29682d1d418eSSumit Saxena 	sc->mpi3mr_flags |= MPI3MR_FLAGS_PORT_ENABLE_DONE;
29692d1d418eSSumit Saxena 	mpi3mr_startup_decrement(sc->cam_sc);
29702d1d418eSSumit Saxena }
29712d1d418eSSumit Saxena 
29722d1d418eSSumit Saxena int mpi3mr_issue_port_enable(struct mpi3mr_softc *sc, U8 async)
29732d1d418eSSumit Saxena {
29742d1d418eSSumit Saxena 	Mpi3PortEnableRequest_t pe_req;
29752d1d418eSSumit Saxena 	int retval = 0;
29762d1d418eSSumit Saxena 
29772d1d418eSSumit Saxena 	memset(&pe_req, 0, sizeof(pe_req));
29782d1d418eSSumit Saxena 	mtx_lock(&sc->init_cmds.completion.lock);
29792d1d418eSSumit Saxena 	if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
29802d1d418eSSumit Saxena 		retval = -1;
29812d1d418eSSumit Saxena 		printf(IOCNAME "Issue PortEnable: Init command is in use\n", sc->name);
29822d1d418eSSumit Saxena 		mtx_unlock(&sc->init_cmds.completion.lock);
29832d1d418eSSumit Saxena 		goto out;
29842d1d418eSSumit Saxena 	}
29852d1d418eSSumit Saxena 
29862d1d418eSSumit Saxena 	sc->init_cmds.state = MPI3MR_CMD_PENDING;
29872d1d418eSSumit Saxena 
29882d1d418eSSumit Saxena 	if (async) {
29892d1d418eSSumit Saxena 		sc->init_cmds.is_waiting = 0;
29902d1d418eSSumit Saxena 		sc->init_cmds.callback = mpi3mr_port_enable_complete;
29912d1d418eSSumit Saxena 	} else {
29922d1d418eSSumit Saxena 		sc->init_cmds.is_waiting = 1;
29932d1d418eSSumit Saxena 		sc->init_cmds.callback = NULL;
29942d1d418eSSumit Saxena 		init_completion(&sc->init_cmds.completion);
29952d1d418eSSumit Saxena 	}
29962d1d418eSSumit Saxena 	pe_req.HostTag = MPI3MR_HOSTTAG_INITCMDS;
29972d1d418eSSumit Saxena 	pe_req.Function = MPI3_FUNCTION_PORT_ENABLE;
29982d1d418eSSumit Saxena 
29992d1d418eSSumit Saxena 	printf(IOCNAME "Sending Port Enable Request\n", sc->name);
30002d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &pe_req, sizeof(pe_req));
30012d1d418eSSumit Saxena 	if (retval) {
30022d1d418eSSumit Saxena 		printf(IOCNAME "Issue PortEnable: Admin Post failed\n",
30032d1d418eSSumit Saxena 		    sc->name);
30042d1d418eSSumit Saxena 		goto out_unlock;
30052d1d418eSSumit Saxena 	}
30062d1d418eSSumit Saxena 
30072d1d418eSSumit Saxena 	if (!async) {
30082d1d418eSSumit Saxena 		wait_for_completion_timeout(&sc->init_cmds.completion,
30092d1d418eSSumit Saxena 		    MPI3MR_PORTENABLE_TIMEOUT);
30102d1d418eSSumit Saxena 		if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
30112d1d418eSSumit Saxena 			printf(IOCNAME "Issue PortEnable: command timed out\n",
30122d1d418eSSumit Saxena 			    sc->name);
30132d1d418eSSumit Saxena 			retval = -1;
30142d1d418eSSumit Saxena 			mpi3mr_check_rh_fault_ioc(sc, MPI3MR_RESET_FROM_PE_TIMEOUT);
30152d1d418eSSumit Saxena 			goto out_unlock;
30162d1d418eSSumit Saxena 		}
30172d1d418eSSumit Saxena 		mpi3mr_port_enable_complete(sc, &sc->init_cmds);
30182d1d418eSSumit Saxena 	}
30192d1d418eSSumit Saxena out_unlock:
30202d1d418eSSumit Saxena 	mtx_unlock(&sc->init_cmds.completion.lock);
30212d1d418eSSumit Saxena 
30222d1d418eSSumit Saxena out:
30232d1d418eSSumit Saxena 	return retval;
30242d1d418eSSumit Saxena }
30252d1d418eSSumit Saxena 
30262d1d418eSSumit Saxena void
30272d1d418eSSumit Saxena mpi3mr_watchdog_thread(void *arg)
30282d1d418eSSumit Saxena {
30292d1d418eSSumit Saxena 	struct mpi3mr_softc *sc;
30302d1d418eSSumit Saxena 	enum mpi3mr_iocstate ioc_state;
30312d1d418eSSumit Saxena 	U32 fault, host_diagnostic, ioc_status;
30322d1d418eSSumit Saxena 
30332d1d418eSSumit Saxena 	sc = (struct mpi3mr_softc *)arg;
30342d1d418eSSumit Saxena 
30352d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "%s\n", __func__);
30362d1d418eSSumit Saxena 
30372d1d418eSSumit Saxena 	sc->watchdog_thread_active = 1;
30382d1d418eSSumit Saxena 	mtx_lock(&sc->reset_mutex);
30392d1d418eSSumit Saxena 	for (;;) {
30402d1d418eSSumit Saxena 		if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN ||
30412d1d418eSSumit Saxena 		    (sc->unrecoverable == 1)) {
30422d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO,
30432d1d418eSSumit Saxena 			    "Exit due to %s from %s\n",
30442d1d418eSSumit Saxena 			   sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN ? "Shutdown" :
30452d1d418eSSumit Saxena 			    "Hardware critical error", __func__);
30462d1d418eSSumit Saxena 			break;
30472d1d418eSSumit Saxena 		}
3048*7c491309SWarner Losh 		mtx_unlock(&sc->reset_mutex);
30492d1d418eSSumit Saxena 
30502d1d418eSSumit Saxena 		if ((sc->prepare_for_reset) &&
30512d1d418eSSumit Saxena 		    ((sc->prepare_for_reset_timeout_counter++) >=
30522d1d418eSSumit Saxena 		     MPI3MR_PREPARE_FOR_RESET_TIMEOUT)) {
30532d1d418eSSumit Saxena 			mpi3mr_soft_reset_handler(sc,
30542d1d418eSSumit Saxena 			    MPI3MR_RESET_FROM_CIACTVRST_TIMER, 1);
3055*7c491309SWarner Losh 			goto sleep;
30562d1d418eSSumit Saxena 		}
30572d1d418eSSumit Saxena 
30582d1d418eSSumit Saxena 		ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
30592d1d418eSSumit Saxena 
30602d1d418eSSumit Saxena 		if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
30612d1d418eSSumit Saxena 			mpi3mr_soft_reset_handler(sc, MPI3MR_RESET_FROM_FIRMWARE, 0);
3062*7c491309SWarner Losh 			goto sleep;
30632d1d418eSSumit Saxena 		}
30642d1d418eSSumit Saxena 
30652d1d418eSSumit Saxena 		ioc_state = mpi3mr_get_iocstate(sc);
30662d1d418eSSumit Saxena 		if (ioc_state == MRIOC_STATE_FAULT) {
30672d1d418eSSumit Saxena 			fault = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_OFFSET) &
30682d1d418eSSumit Saxena 			    MPI3_SYSIF_FAULT_CODE_MASK;
30692d1d418eSSumit Saxena 
30702d1d418eSSumit Saxena 			host_diagnostic = mpi3mr_regread(sc, MPI3_SYSIF_HOST_DIAG_OFFSET);
30712d1d418eSSumit Saxena 			if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) {
30722d1d418eSSumit Saxena 				if (!sc->diagsave_timeout) {
30732d1d418eSSumit Saxena 					mpi3mr_print_fault_info(sc);
30742d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_INFO,
30752d1d418eSSumit Saxena 						"diag save in progress\n");
30762d1d418eSSumit Saxena 				}
30772d1d418eSSumit Saxena 				if ((sc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT)
3078*7c491309SWarner Losh 					goto sleep;
30792d1d418eSSumit Saxena 			}
30802d1d418eSSumit Saxena 			mpi3mr_print_fault_info(sc);
30812d1d418eSSumit Saxena 			sc->diagsave_timeout = 0;
30822d1d418eSSumit Saxena 
30832d1d418eSSumit Saxena 			if ((fault == MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED) ||
30842d1d418eSSumit Saxena 			    (fault == MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED)) {
30852d1d418eSSumit Saxena 				mpi3mr_dprint(sc, MPI3MR_INFO,
30862d1d418eSSumit Saxena 				    "Controller requires system power cycle or complete reset is needed,"
30872d1d418eSSumit Saxena 				    "fault code: 0x%x. marking controller as unrecoverable\n", fault);
30882d1d418eSSumit Saxena 				sc->unrecoverable = 1;
3089*7c491309SWarner Losh 				break;
30902d1d418eSSumit Saxena 			}
30912d1d418eSSumit Saxena 			if ((fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET)
30922d1d418eSSumit Saxena 			    || (fault == MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS)
30932d1d418eSSumit Saxena 			    || (sc->reset_in_progress))
3094*7c491309SWarner Losh 				break;
30952d1d418eSSumit Saxena 			if (fault == MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET)
30962d1d418eSSumit Saxena 				mpi3mr_soft_reset_handler(sc,
30972d1d418eSSumit Saxena 				    MPI3MR_RESET_FROM_CIACTIV_FAULT, 0);
30982d1d418eSSumit Saxena 			else
30992d1d418eSSumit Saxena 				mpi3mr_soft_reset_handler(sc,
31002d1d418eSSumit Saxena 				    MPI3MR_RESET_FROM_FAULT_WATCH, 0);
31012d1d418eSSumit Saxena 
31022d1d418eSSumit Saxena 		}
31032d1d418eSSumit Saxena 
31042d1d418eSSumit Saxena 		if (sc->reset.type == MPI3MR_TRIGGER_SOFT_RESET) {
31052d1d418eSSumit Saxena 			mpi3mr_print_fault_info(sc);
31062d1d418eSSumit Saxena 			mpi3mr_soft_reset_handler(sc, sc->reset.reason, 1);
31072d1d418eSSumit Saxena 		}
3108*7c491309SWarner Losh sleep:
3109*7c491309SWarner Losh 		mtx_lock(&sc->reset_mutex);
3110*7c491309SWarner Losh 		/*
3111*7c491309SWarner Losh 		 * Sleep for 1 second if we're not exiting, then loop to top
3112*7c491309SWarner Losh 		 * to poll exit status and hardware health.
3113*7c491309SWarner Losh 		 */
3114*7c491309SWarner Losh 		if ((sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) == 0 &&
3115*7c491309SWarner Losh 		    !sc->unrecoverable) {
3116*7c491309SWarner Losh 			msleep(&sc->watchdog_chan, &sc->reset_mutex, PRIBIO,
3117*7c491309SWarner Losh 			    "mpi3mr_watchdog", 1 * hz);
31182d1d418eSSumit Saxena 		}
3119*7c491309SWarner Losh 	}
31202d1d418eSSumit Saxena 	mtx_unlock(&sc->reset_mutex);
31212d1d418eSSumit Saxena 	sc->watchdog_thread_active = 0;
31222d1d418eSSumit Saxena 	mpi3mr_kproc_exit(0);
31232d1d418eSSumit Saxena }
31242d1d418eSSumit Saxena 
31252d1d418eSSumit Saxena static void mpi3mr_display_event_data(struct mpi3mr_softc *sc,
31262d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_rep)
31272d1d418eSSumit Saxena {
31282d1d418eSSumit Saxena 	char *desc = NULL;
31292d1d418eSSumit Saxena 	U16 event;
31302d1d418eSSumit Saxena 
31312d1d418eSSumit Saxena 	event = event_rep->Event;
31322d1d418eSSumit Saxena 
31332d1d418eSSumit Saxena 	switch (event) {
31342d1d418eSSumit Saxena 	case MPI3_EVENT_LOG_DATA:
31352d1d418eSSumit Saxena 		desc = "Log Data";
31362d1d418eSSumit Saxena 		break;
31372d1d418eSSumit Saxena 	case MPI3_EVENT_CHANGE:
31382d1d418eSSumit Saxena 		desc = "Event Change";
31392d1d418eSSumit Saxena 		break;
31402d1d418eSSumit Saxena 	case MPI3_EVENT_GPIO_INTERRUPT:
31412d1d418eSSumit Saxena 		desc = "GPIO Interrupt";
31422d1d418eSSumit Saxena 		break;
31432d1d418eSSumit Saxena 	case MPI3_EVENT_CABLE_MGMT:
31442d1d418eSSumit Saxena 		desc = "Cable Management";
31452d1d418eSSumit Saxena 		break;
31462d1d418eSSumit Saxena 	case MPI3_EVENT_ENERGY_PACK_CHANGE:
31472d1d418eSSumit Saxena 		desc = "Energy Pack Change";
31482d1d418eSSumit Saxena 		break;
31492d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_ADDED:
31502d1d418eSSumit Saxena 	{
31512d1d418eSSumit Saxena 		Mpi3DevicePage0_t *event_data =
31522d1d418eSSumit Saxena 		    (Mpi3DevicePage0_t *)event_rep->EventData;
31532d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "Device Added: Dev=0x%04x Form=0x%x Perst id: 0x%x\n",
31542d1d418eSSumit Saxena 			event_data->DevHandle, event_data->DeviceForm, event_data->PersistentID);
31552d1d418eSSumit Saxena 		return;
31562d1d418eSSumit Saxena 	}
31572d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
31582d1d418eSSumit Saxena 	{
31592d1d418eSSumit Saxena 		Mpi3DevicePage0_t *event_data =
31602d1d418eSSumit Saxena 		    (Mpi3DevicePage0_t *)event_rep->EventData;
31612d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "Device Info Changed: Dev=0x%04x Form=0x%x\n",
31622d1d418eSSumit Saxena 			event_data->DevHandle, event_data->DeviceForm);
31632d1d418eSSumit Saxena 		return;
31642d1d418eSSumit Saxena 	}
31652d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
31662d1d418eSSumit Saxena 	{
31672d1d418eSSumit Saxena 		Mpi3EventDataDeviceStatusChange_t *event_data =
31682d1d418eSSumit Saxena 		    (Mpi3EventDataDeviceStatusChange_t *)event_rep->EventData;
31692d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "Device Status Change: Dev=0x%04x RC=0x%x\n",
31702d1d418eSSumit Saxena 			event_data->DevHandle, event_data->ReasonCode);
31712d1d418eSSumit Saxena 		return;
31722d1d418eSSumit Saxena 	}
31732d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_DISCOVERY:
31742d1d418eSSumit Saxena 	{
31752d1d418eSSumit Saxena 		Mpi3EventDataSasDiscovery_t *event_data =
31762d1d418eSSumit Saxena 		    (Mpi3EventDataSasDiscovery_t *)event_rep->EventData;
31772d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "SAS Discovery: (%s)",
31782d1d418eSSumit Saxena 			(event_data->ReasonCode == MPI3_EVENT_SAS_DISC_RC_STARTED) ?
31792d1d418eSSumit Saxena 		    "start" : "stop");
31802d1d418eSSumit Saxena 		if (event_data->DiscoveryStatus &&
31812d1d418eSSumit Saxena 		    (sc->mpi3mr_debug & MPI3MR_EVENT)) {
31822d1d418eSSumit Saxena 			printf("discovery_status(0x%08x)",
31832d1d418eSSumit Saxena 			    event_data->DiscoveryStatus);
31842d1d418eSSumit Saxena 
31852d1d418eSSumit Saxena 		}
31862d1d418eSSumit Saxena 
31872d1d418eSSumit Saxena 		if (sc->mpi3mr_debug & MPI3MR_EVENT)
31882d1d418eSSumit Saxena 			printf("\n");
31892d1d418eSSumit Saxena 		return;
31902d1d418eSSumit Saxena 	}
31912d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
31922d1d418eSSumit Saxena 		desc = "SAS Broadcast Primitive";
31932d1d418eSSumit Saxena 		break;
31942d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_NOTIFY_PRIMITIVE:
31952d1d418eSSumit Saxena 		desc = "SAS Notify Primitive";
31962d1d418eSSumit Saxena 		break;
31972d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
31982d1d418eSSumit Saxena 		desc = "SAS Init Device Status Change";
31992d1d418eSSumit Saxena 		break;
32002d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW:
32012d1d418eSSumit Saxena 		desc = "SAS Init Table Overflow";
32022d1d418eSSumit Saxena 		break;
32032d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
32042d1d418eSSumit Saxena 		desc = "SAS Topology Change List";
32052d1d418eSSumit Saxena 		break;
32062d1d418eSSumit Saxena 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
32072d1d418eSSumit Saxena 		desc = "Enclosure Device Status Change";
32082d1d418eSSumit Saxena 		break;
32092d1d418eSSumit Saxena 	case MPI3_EVENT_HARD_RESET_RECEIVED:
32102d1d418eSSumit Saxena 		desc = "Hard Reset Received";
32112d1d418eSSumit Saxena 		break;
32122d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_PHY_COUNTER:
32132d1d418eSSumit Saxena 		desc = "SAS PHY Counter";
32142d1d418eSSumit Saxena 		break;
32152d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
32162d1d418eSSumit Saxena 		desc = "SAS Device Discovery Error";
32172d1d418eSSumit Saxena 		break;
32182d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
32192d1d418eSSumit Saxena 		desc = "PCIE Topology Change List";
32202d1d418eSSumit Saxena 		break;
32212d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_ENUMERATION:
32222d1d418eSSumit Saxena 	{
32232d1d418eSSumit Saxena 		Mpi3EventDataPcieEnumeration_t *event_data =
32242d1d418eSSumit Saxena 			(Mpi3EventDataPcieEnumeration_t *)event_rep->EventData;
32252d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "PCIE Enumeration: (%s)",
32262d1d418eSSumit Saxena 			(event_data->ReasonCode ==
32272d1d418eSSumit Saxena 			    MPI3_EVENT_PCIE_ENUM_RC_STARTED) ? "start" :
32282d1d418eSSumit Saxena 			    "stop");
32292d1d418eSSumit Saxena 		if (event_data->EnumerationStatus)
32302d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_EVENT, "enumeration_status(0x%08x)",
32312d1d418eSSumit Saxena 			   event_data->EnumerationStatus);
32322d1d418eSSumit Saxena 		if (sc->mpi3mr_debug & MPI3MR_EVENT)
32332d1d418eSSumit Saxena 			printf("\n");
32342d1d418eSSumit Saxena 		return;
32352d1d418eSSumit Saxena 	}
32362d1d418eSSumit Saxena 	case MPI3_EVENT_PREPARE_FOR_RESET:
32372d1d418eSSumit Saxena 		desc = "Prepare For Reset";
32382d1d418eSSumit Saxena 		break;
32392d1d418eSSumit Saxena 	}
32402d1d418eSSumit Saxena 
32412d1d418eSSumit Saxena 	if (!desc)
32422d1d418eSSumit Saxena 		return;
32432d1d418eSSumit Saxena 
32442d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT, "%s\n", desc);
32452d1d418eSSumit Saxena }
32462d1d418eSSumit Saxena 
32472d1d418eSSumit Saxena struct mpi3mr_target *
32482d1d418eSSumit Saxena mpi3mr_find_target_by_per_id(struct mpi3mr_cam_softc *cam_sc,
32492d1d418eSSumit Saxena     uint16_t per_id)
32502d1d418eSSumit Saxena {
32512d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
32522d1d418eSSumit Saxena 
32532d1d418eSSumit Saxena 	mtx_lock_spin(&cam_sc->sc->target_lock);
32542d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &cam_sc->tgt_list, tgt_next) {
32552d1d418eSSumit Saxena 		if (target->per_id == per_id)
32562d1d418eSSumit Saxena 			break;
32572d1d418eSSumit Saxena 	}
32582d1d418eSSumit Saxena 
32592d1d418eSSumit Saxena 	mtx_unlock_spin(&cam_sc->sc->target_lock);
32602d1d418eSSumit Saxena 	return target;
32612d1d418eSSumit Saxena }
32622d1d418eSSumit Saxena 
32632d1d418eSSumit Saxena struct mpi3mr_target *
32642d1d418eSSumit Saxena mpi3mr_find_target_by_dev_handle(struct mpi3mr_cam_softc *cam_sc,
32652d1d418eSSumit Saxena     uint16_t handle)
32662d1d418eSSumit Saxena {
32672d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
32682d1d418eSSumit Saxena 
32692d1d418eSSumit Saxena 	mtx_lock_spin(&cam_sc->sc->target_lock);
32702d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &cam_sc->tgt_list, tgt_next) {
32712d1d418eSSumit Saxena 		if (target->dev_handle == handle)
32722d1d418eSSumit Saxena 			break;
32732d1d418eSSumit Saxena 
32742d1d418eSSumit Saxena 	}
32752d1d418eSSumit Saxena 	mtx_unlock_spin(&cam_sc->sc->target_lock);
32762d1d418eSSumit Saxena 	return target;
32772d1d418eSSumit Saxena }
32782d1d418eSSumit Saxena 
32792d1d418eSSumit Saxena void mpi3mr_update_device(struct mpi3mr_softc *sc,
32802d1d418eSSumit Saxena     struct mpi3mr_target *tgtdev, Mpi3DevicePage0_t *dev_pg0,
32812d1d418eSSumit Saxena     bool is_added)
32822d1d418eSSumit Saxena {
32832d1d418eSSumit Saxena 	U16 flags = 0;
32842d1d418eSSumit Saxena 
32852d1d418eSSumit Saxena 	tgtdev->per_id = (dev_pg0->PersistentID);
32862d1d418eSSumit Saxena 	tgtdev->dev_handle = (dev_pg0->DevHandle);
32872d1d418eSSumit Saxena 	tgtdev->dev_type = dev_pg0->DeviceForm;
32882d1d418eSSumit Saxena 	tgtdev->encl_handle = (dev_pg0->EnclosureHandle);
32892d1d418eSSumit Saxena 	tgtdev->parent_handle = (dev_pg0->ParentDevHandle);
32902d1d418eSSumit Saxena 	tgtdev->slot = (dev_pg0->Slot);
32912d1d418eSSumit Saxena 	tgtdev->qdepth = (dev_pg0->QueueDepth);
32922d1d418eSSumit Saxena 	tgtdev->wwid = (dev_pg0->WWID);
32932d1d418eSSumit Saxena 
32942d1d418eSSumit Saxena 	flags = (dev_pg0->Flags);
32952d1d418eSSumit Saxena 	tgtdev->is_hidden = (flags & MPI3_DEVICE0_FLAGS_HIDDEN);
32962d1d418eSSumit Saxena 	if (is_added == true)
32972d1d418eSSumit Saxena 		tgtdev->io_throttle_enabled =
32982d1d418eSSumit Saxena 		    (flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0;
32992d1d418eSSumit Saxena 
33002d1d418eSSumit Saxena 	switch (dev_pg0->AccessStatus) {
33012d1d418eSSumit Saxena 	case MPI3_DEVICE0_ASTATUS_NO_ERRORS:
33022d1d418eSSumit Saxena 	case MPI3_DEVICE0_ASTATUS_PREPARE:
33032d1d418eSSumit Saxena 	case MPI3_DEVICE0_ASTATUS_NEEDS_INITIALIZATION:
33042d1d418eSSumit Saxena 	case MPI3_DEVICE0_ASTATUS_DEVICE_MISSING_DELAY:
33052d1d418eSSumit Saxena 		break;
33062d1d418eSSumit Saxena 	default:
33072d1d418eSSumit Saxena 		tgtdev->is_hidden = 1;
33082d1d418eSSumit Saxena 		break;
33092d1d418eSSumit Saxena 	}
33102d1d418eSSumit Saxena 
33112d1d418eSSumit Saxena 	switch (tgtdev->dev_type) {
33122d1d418eSSumit Saxena 	case MPI3_DEVICE_DEVFORM_SAS_SATA:
33132d1d418eSSumit Saxena 	{
33142d1d418eSSumit Saxena 		Mpi3Device0SasSataFormat_t *sasinf =
33152d1d418eSSumit Saxena 		    &dev_pg0->DeviceSpecific.SasSataFormat;
33162d1d418eSSumit Saxena 		U16 dev_info = (sasinf->DeviceInfo);
33172d1d418eSSumit Saxena 		tgtdev->dev_spec.sassata_inf.dev_info = dev_info;
33182d1d418eSSumit Saxena 		tgtdev->dev_spec.sassata_inf.sas_address =
33192d1d418eSSumit Saxena 		    (sasinf->SASAddress);
33202d1d418eSSumit Saxena 		if ((dev_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) !=
33212d1d418eSSumit Saxena 		    MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE)
33222d1d418eSSumit Saxena 			tgtdev->is_hidden = 1;
33232d1d418eSSumit Saxena 		else if (!(dev_info & (MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET |
33242d1d418eSSumit Saxena 			    MPI3_SAS_DEVICE_INFO_SSP_TARGET)))
33252d1d418eSSumit Saxena 			tgtdev->is_hidden = 1;
33262d1d418eSSumit Saxena 		break;
33272d1d418eSSumit Saxena 	}
33282d1d418eSSumit Saxena 	case MPI3_DEVICE_DEVFORM_PCIE:
33292d1d418eSSumit Saxena 	{
33302d1d418eSSumit Saxena 		Mpi3Device0PcieFormat_t *pcieinf =
33312d1d418eSSumit Saxena 		    &dev_pg0->DeviceSpecific.PcieFormat;
33322d1d418eSSumit Saxena 		U16 dev_info = (pcieinf->DeviceInfo);
33332d1d418eSSumit Saxena 
33342d1d418eSSumit Saxena 		tgtdev->q_depth = dev_pg0->QueueDepth;
33352d1d418eSSumit Saxena 		tgtdev->dev_spec.pcie_inf.dev_info = dev_info;
33362d1d418eSSumit Saxena 		tgtdev->dev_spec.pcie_inf.capb =
33372d1d418eSSumit Saxena 		    (pcieinf->Capabilities);
33382d1d418eSSumit Saxena 		tgtdev->dev_spec.pcie_inf.mdts = MPI3MR_DEFAULT_MDTS;
33392d1d418eSSumit Saxena 		if (dev_pg0->AccessStatus == MPI3_DEVICE0_ASTATUS_NO_ERRORS) {
33402d1d418eSSumit Saxena 			tgtdev->dev_spec.pcie_inf.mdts =
33412d1d418eSSumit Saxena 			    (pcieinf->MaximumDataTransferSize);
33422d1d418eSSumit Saxena 			tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->PageSize;
33432d1d418eSSumit Saxena 			tgtdev->dev_spec.pcie_inf.reset_to =
33442d1d418eSSumit Saxena 				pcieinf->ControllerResetTO;
33452d1d418eSSumit Saxena 			tgtdev->dev_spec.pcie_inf.abort_to =
33462d1d418eSSumit Saxena 				pcieinf->NVMeAbortTO;
33472d1d418eSSumit Saxena 		}
33482d1d418eSSumit Saxena 		if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024))
33492d1d418eSSumit Saxena 			tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024);
33502d1d418eSSumit Saxena 
33512d1d418eSSumit Saxena 		if (((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
33522d1d418eSSumit Saxena 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) &&
33532d1d418eSSumit Saxena 		    ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
33542d1d418eSSumit Saxena 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE))
33552d1d418eSSumit Saxena 			tgtdev->is_hidden = 1;
33562d1d418eSSumit Saxena 
33572d1d418eSSumit Saxena 		break;
33582d1d418eSSumit Saxena 	}
33592d1d418eSSumit Saxena 	case MPI3_DEVICE_DEVFORM_VD:
33602d1d418eSSumit Saxena 	{
33612d1d418eSSumit Saxena 		Mpi3Device0VdFormat_t *vdinf =
33622d1d418eSSumit Saxena 		    &dev_pg0->DeviceSpecific.VdFormat;
33632d1d418eSSumit Saxena 		struct mpi3mr_throttle_group_info *tg = NULL;
33642d1d418eSSumit Saxena 
33652d1d418eSSumit Saxena 		tgtdev->dev_spec.vol_inf.state = vdinf->VdState;
33662d1d418eSSumit Saxena 		if (vdinf->VdState == MPI3_DEVICE0_VD_STATE_OFFLINE)
33672d1d418eSSumit Saxena 			tgtdev->is_hidden = 1;
33682d1d418eSSumit Saxena 		tgtdev->dev_spec.vol_inf.tg_id = vdinf->IOThrottleGroup;
33692d1d418eSSumit Saxena 		tgtdev->dev_spec.vol_inf.tg_high =
33702d1d418eSSumit Saxena 			vdinf->IOThrottleGroupHigh * 2048;
33712d1d418eSSumit Saxena 		tgtdev->dev_spec.vol_inf.tg_low =
33722d1d418eSSumit Saxena 			vdinf->IOThrottleGroupLow * 2048;
33732d1d418eSSumit Saxena 		if (vdinf->IOThrottleGroup < sc->num_io_throttle_group) {
33742d1d418eSSumit Saxena 			tg = sc->throttle_groups + vdinf->IOThrottleGroup;
33752d1d418eSSumit Saxena 			tg->id = vdinf->IOThrottleGroup;
33762d1d418eSSumit Saxena 			tg->high = tgtdev->dev_spec.vol_inf.tg_high;
33772d1d418eSSumit Saxena 			tg->low = tgtdev->dev_spec.vol_inf.tg_low;
33782d1d418eSSumit Saxena 			if (is_added == true)
33792d1d418eSSumit Saxena 				tg->fw_qd = tgtdev->q_depth;
33802d1d418eSSumit Saxena 			tg->modified_qd = tgtdev->q_depth;
33812d1d418eSSumit Saxena 		}
33822d1d418eSSumit Saxena 		tgtdev->dev_spec.vol_inf.tg = tg;
33832d1d418eSSumit Saxena 		tgtdev->throttle_group = tg;
33842d1d418eSSumit Saxena 		break;
33852d1d418eSSumit Saxena 	}
33862d1d418eSSumit Saxena 	default:
33872d1d418eSSumit Saxena 		goto out;
33882d1d418eSSumit Saxena 	}
33892d1d418eSSumit Saxena 
33902d1d418eSSumit Saxena out:
33912d1d418eSSumit Saxena 	return;
33922d1d418eSSumit Saxena }
33932d1d418eSSumit Saxena 
33942d1d418eSSumit Saxena int mpi3mr_create_device(struct mpi3mr_softc *sc,
33952d1d418eSSumit Saxena     Mpi3DevicePage0_t *dev_pg0)
33962d1d418eSSumit Saxena {
33972d1d418eSSumit Saxena 	int retval = 0;
33982d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
33992d1d418eSSumit Saxena 	U16 per_id = 0;
34002d1d418eSSumit Saxena 
34012d1d418eSSumit Saxena 	per_id = dev_pg0->PersistentID;
34022d1d418eSSumit Saxena 
34032d1d418eSSumit Saxena 	mtx_lock_spin(&sc->target_lock);
34042d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) {
34052d1d418eSSumit Saxena 		if (target->per_id == per_id) {
34062d1d418eSSumit Saxena 			target->state = MPI3MR_DEV_CREATED;
34072d1d418eSSumit Saxena 			break;
34082d1d418eSSumit Saxena 		}
34092d1d418eSSumit Saxena 	}
34102d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->target_lock);
34112d1d418eSSumit Saxena 
34122d1d418eSSumit Saxena 	if (target) {
34132d1d418eSSumit Saxena 			mpi3mr_update_device(sc, target, dev_pg0, true);
34142d1d418eSSumit Saxena 	} else {
34152d1d418eSSumit Saxena 			target = malloc(sizeof(*target), M_MPI3MR,
34162d1d418eSSumit Saxena 				 M_NOWAIT | M_ZERO);
34172d1d418eSSumit Saxena 
34182d1d418eSSumit Saxena 			if (target == NULL) {
34192d1d418eSSumit Saxena 				retval = -1;
34202d1d418eSSumit Saxena 				goto out;
34212d1d418eSSumit Saxena 			}
34222d1d418eSSumit Saxena 
34232d1d418eSSumit Saxena 			target->exposed_to_os = 0;
34242d1d418eSSumit Saxena 			mpi3mr_update_device(sc, target, dev_pg0, true);
34252d1d418eSSumit Saxena 			mtx_lock_spin(&sc->target_lock);
34262d1d418eSSumit Saxena 			TAILQ_INSERT_TAIL(&sc->cam_sc->tgt_list, target, tgt_next);
34272d1d418eSSumit Saxena 			target->state = MPI3MR_DEV_CREATED;
34282d1d418eSSumit Saxena 			mtx_unlock_spin(&sc->target_lock);
34292d1d418eSSumit Saxena 	}
34302d1d418eSSumit Saxena out:
34312d1d418eSSumit Saxena 	return retval;
34322d1d418eSSumit Saxena }
34332d1d418eSSumit Saxena 
34342d1d418eSSumit Saxena /**
34352d1d418eSSumit Saxena  * mpi3mr_dev_rmhs_complete_iou - Device removal IOUC completion
34362d1d418eSSumit Saxena  * @sc: Adapter instance reference
34372d1d418eSSumit Saxena  * @drv_cmd: Internal command tracker
34382d1d418eSSumit Saxena  *
34392d1d418eSSumit Saxena  * Issues a target reset TM to the firmware from the device
34402d1d418eSSumit Saxena  * removal TM pend list or retry the removal handshake sequence
34412d1d418eSSumit Saxena  * based on the IOU control request IOC status.
34422d1d418eSSumit Saxena  *
34432d1d418eSSumit Saxena  * Return: Nothing
34442d1d418eSSumit Saxena  */
34452d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_softc *sc,
34462d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd)
34472d1d418eSSumit Saxena {
34482d1d418eSSumit Saxena 	U16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
34492d1d418eSSumit Saxena 	struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
34502d1d418eSSumit Saxena 
34512d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT,
34522d1d418eSSumit Saxena 	    "%s :dev_rmhs_iouctrl_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x)\n",
34532d1d418eSSumit Saxena 	    __func__, drv_cmd->dev_handle, drv_cmd->ioc_status,
34542d1d418eSSumit Saxena 	    drv_cmd->ioc_loginfo);
34552d1d418eSSumit Saxena 	if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) {
34562d1d418eSSumit Saxena 		if (drv_cmd->retry_count < MPI3MR_DEVRMHS_RETRYCOUNT) {
34572d1d418eSSumit Saxena 			drv_cmd->retry_count++;
34582d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_EVENT,
34592d1d418eSSumit Saxena 			    "%s :dev_rmhs_iouctrl_complete: handle(0x%04x)retrying handshake retry=%d\n",
34602d1d418eSSumit Saxena 			    __func__, drv_cmd->dev_handle,
34612d1d418eSSumit Saxena 			    drv_cmd->retry_count);
34622d1d418eSSumit Saxena 			mpi3mr_dev_rmhs_send_tm(sc, drv_cmd->dev_handle,
34632d1d418eSSumit Saxena 			    drv_cmd, drv_cmd->iou_rc);
34642d1d418eSSumit Saxena 			return;
34652d1d418eSSumit Saxena 		}
34662d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
34672d1d418eSSumit Saxena 		    "%s :dev removal handshake failed after all retries: handle(0x%04x)\n",
34682d1d418eSSumit Saxena 		    __func__, drv_cmd->dev_handle);
34692d1d418eSSumit Saxena 	} else {
34702d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
34712d1d418eSSumit Saxena 		    "%s :dev removal handshake completed successfully: handle(0x%04x)\n",
34722d1d418eSSumit Saxena 		    __func__, drv_cmd->dev_handle);
34732d1d418eSSumit Saxena 		mpi3mr_clear_bit(drv_cmd->dev_handle, sc->removepend_bitmap);
34742d1d418eSSumit Saxena 	}
34752d1d418eSSumit Saxena 
34762d1d418eSSumit Saxena 	if (!TAILQ_EMPTY(&sc->delayed_rmhs_list)) {
34772d1d418eSSumit Saxena 		delayed_dev_rmhs = TAILQ_FIRST(&sc->delayed_rmhs_list);
34782d1d418eSSumit Saxena 		drv_cmd->dev_handle = delayed_dev_rmhs->handle;
34792d1d418eSSumit Saxena 		drv_cmd->retry_count = 0;
34802d1d418eSSumit Saxena 		drv_cmd->iou_rc = delayed_dev_rmhs->iou_rc;
34812d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT,
34822d1d418eSSumit Saxena 		    "%s :dev_rmhs_iouctrl_complete: processing delayed TM: handle(0x%04x)\n",
34832d1d418eSSumit Saxena 		    __func__, drv_cmd->dev_handle);
34842d1d418eSSumit Saxena 		mpi3mr_dev_rmhs_send_tm(sc, drv_cmd->dev_handle, drv_cmd,
34852d1d418eSSumit Saxena 		    drv_cmd->iou_rc);
34862d1d418eSSumit Saxena 		TAILQ_REMOVE(&sc->delayed_rmhs_list, delayed_dev_rmhs, list);
34872d1d418eSSumit Saxena 		free(delayed_dev_rmhs, M_MPI3MR);
34882d1d418eSSumit Saxena 		return;
34892d1d418eSSumit Saxena 	}
34902d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
34912d1d418eSSumit Saxena 	drv_cmd->callback = NULL;
34922d1d418eSSumit Saxena 	drv_cmd->retry_count = 0;
34932d1d418eSSumit Saxena 	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
34942d1d418eSSumit Saxena 	mpi3mr_clear_bit(cmd_idx, sc->devrem_bitmap);
34952d1d418eSSumit Saxena }
34962d1d418eSSumit Saxena 
34972d1d418eSSumit Saxena /**
34982d1d418eSSumit Saxena  * mpi3mr_dev_rmhs_complete_tm - Device removal TM completion
34992d1d418eSSumit Saxena  * @sc: Adapter instance reference
35002d1d418eSSumit Saxena  * @drv_cmd: Internal command tracker
35012d1d418eSSumit Saxena  *
35022d1d418eSSumit Saxena  * Issues a target reset TM to the firmware from the device
35032d1d418eSSumit Saxena  * removal TM pend list or issue IO Unit control request as
35042d1d418eSSumit Saxena  * part of device removal or hidden acknowledgment handshake.
35052d1d418eSSumit Saxena  *
35062d1d418eSSumit Saxena  * Return: Nothing
35072d1d418eSSumit Saxena  */
35082d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_complete_tm(struct mpi3mr_softc *sc,
35092d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd)
35102d1d418eSSumit Saxena {
35112d1d418eSSumit Saxena 	Mpi3IoUnitControlRequest_t iou_ctrl;
35122d1d418eSSumit Saxena 	U16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
35132d1d418eSSumit Saxena 	Mpi3SCSITaskMgmtReply_t *tm_reply = NULL;
35142d1d418eSSumit Saxena 	int retval;
35152d1d418eSSumit Saxena 
35162d1d418eSSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_REPLYVALID)
35172d1d418eSSumit Saxena 		tm_reply = (Mpi3SCSITaskMgmtReply_t *)drv_cmd->reply;
35182d1d418eSSumit Saxena 
35192d1d418eSSumit Saxena 	if (tm_reply)
35202d1d418eSSumit Saxena 		printf(IOCNAME
35212d1d418eSSumit Saxena 		    "dev_rmhs_tr_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x), term_count(%d)\n",
35222d1d418eSSumit Saxena 		    sc->name, drv_cmd->dev_handle, drv_cmd->ioc_status,
35232d1d418eSSumit Saxena 		    drv_cmd->ioc_loginfo,
35242d1d418eSSumit Saxena 		    le32toh(tm_reply->TerminationCount));
35252d1d418eSSumit Saxena 
35262d1d418eSSumit Saxena 	printf(IOCNAME "Issuing IOU CTL: handle(0x%04x) dev_rmhs idx(%d)\n",
35272d1d418eSSumit Saxena 	    sc->name, drv_cmd->dev_handle, cmd_idx);
35282d1d418eSSumit Saxena 
35292d1d418eSSumit Saxena 	memset(&iou_ctrl, 0, sizeof(iou_ctrl));
35302d1d418eSSumit Saxena 
35312d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_PENDING;
35322d1d418eSSumit Saxena 	drv_cmd->is_waiting = 0;
35332d1d418eSSumit Saxena 	drv_cmd->callback = mpi3mr_dev_rmhs_complete_iou;
35342d1d418eSSumit Saxena 	iou_ctrl.Operation = drv_cmd->iou_rc;
35352d1d418eSSumit Saxena 	iou_ctrl.Param16[0] = htole16(drv_cmd->dev_handle);
35362d1d418eSSumit Saxena 	iou_ctrl.HostTag = htole16(drv_cmd->host_tag);
35372d1d418eSSumit Saxena 	iou_ctrl.Function = MPI3_FUNCTION_IO_UNIT_CONTROL;
35382d1d418eSSumit Saxena 
35392d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &iou_ctrl, sizeof(iou_ctrl));
35402d1d418eSSumit Saxena 	if (retval) {
35412d1d418eSSumit Saxena 		printf(IOCNAME "Issue DevRmHsTMIOUCTL: Admin post failed\n",
35422d1d418eSSumit Saxena 		    sc->name);
35432d1d418eSSumit Saxena 		goto out_failed;
35442d1d418eSSumit Saxena 	}
35452d1d418eSSumit Saxena 
35462d1d418eSSumit Saxena 	return;
35472d1d418eSSumit Saxena out_failed:
35482d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
35492d1d418eSSumit Saxena 	drv_cmd->callback = NULL;
35502d1d418eSSumit Saxena 	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
35512d1d418eSSumit Saxena 	drv_cmd->retry_count = 0;
35522d1d418eSSumit Saxena 	mpi3mr_clear_bit(cmd_idx, sc->devrem_bitmap);
35532d1d418eSSumit Saxena }
35542d1d418eSSumit Saxena 
35552d1d418eSSumit Saxena /**
35562d1d418eSSumit Saxena  * mpi3mr_dev_rmhs_send_tm - Issue TM for device removal
35572d1d418eSSumit Saxena  * @sc: Adapter instance reference
35582d1d418eSSumit Saxena  * @handle: Device handle
35592d1d418eSSumit Saxena  * @cmdparam: Internal command tracker
35602d1d418eSSumit Saxena  * @iou_rc: IO Unit reason code
35612d1d418eSSumit Saxena  *
35622d1d418eSSumit Saxena  * Issues a target reset TM to the firmware or add it to a pend
35632d1d418eSSumit Saxena  * list as part of device removal or hidden acknowledgment
35642d1d418eSSumit Saxena  * handshake.
35652d1d418eSSumit Saxena  *
35662d1d418eSSumit Saxena  * Return: Nothing
35672d1d418eSSumit Saxena  */
35682d1d418eSSumit Saxena static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_softc *sc, U16 handle,
35692d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdparam, U8 iou_rc)
35702d1d418eSSumit Saxena {
35712d1d418eSSumit Saxena 	Mpi3SCSITaskMgmtRequest_t tm_req;
35722d1d418eSSumit Saxena 	int retval = 0;
35732d1d418eSSumit Saxena 	U16 cmd_idx = MPI3MR_NUM_DEVRMCMD;
35742d1d418eSSumit Saxena 	U8 retrycount = 5;
35752d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd = cmdparam;
35762d1d418eSSumit Saxena 	struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
35772d1d418eSSumit Saxena 	struct mpi3mr_target *tgtdev = NULL;
35782d1d418eSSumit Saxena 
35792d1d418eSSumit Saxena 	mtx_lock_spin(&sc->target_lock);
35802d1d418eSSumit Saxena 	TAILQ_FOREACH(tgtdev, &sc->cam_sc->tgt_list, tgt_next) {
35812d1d418eSSumit Saxena 		if ((tgtdev->dev_handle == handle) &&
35822d1d418eSSumit Saxena 		    (iou_rc == MPI3_CTRL_OP_REMOVE_DEVICE)) {
35832d1d418eSSumit Saxena 			tgtdev->state = MPI3MR_DEV_REMOVE_HS_STARTED;
35842d1d418eSSumit Saxena 			break;
35852d1d418eSSumit Saxena 		}
35862d1d418eSSumit Saxena 	}
35872d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->target_lock);
35882d1d418eSSumit Saxena 
35892d1d418eSSumit Saxena 	if (drv_cmd)
35902d1d418eSSumit Saxena 		goto issue_cmd;
35912d1d418eSSumit Saxena 	do {
35922d1d418eSSumit Saxena 		cmd_idx = mpi3mr_find_first_zero_bit(sc->devrem_bitmap,
35932d1d418eSSumit Saxena 		    MPI3MR_NUM_DEVRMCMD);
35942d1d418eSSumit Saxena 		if (cmd_idx < MPI3MR_NUM_DEVRMCMD) {
35952d1d418eSSumit Saxena 			if (!mpi3mr_test_and_set_bit(cmd_idx, sc->devrem_bitmap))
35962d1d418eSSumit Saxena 				break;
35972d1d418eSSumit Saxena 			cmd_idx = MPI3MR_NUM_DEVRMCMD;
35982d1d418eSSumit Saxena 		}
35992d1d418eSSumit Saxena 	} while (retrycount--);
36002d1d418eSSumit Saxena 
36012d1d418eSSumit Saxena 	if (cmd_idx >= MPI3MR_NUM_DEVRMCMD) {
36022d1d418eSSumit Saxena 		delayed_dev_rmhs = malloc(sizeof(*delayed_dev_rmhs),M_MPI3MR,
36032d1d418eSSumit Saxena 		     M_ZERO|M_NOWAIT);
36042d1d418eSSumit Saxena 
36052d1d418eSSumit Saxena 		if (!delayed_dev_rmhs)
36062d1d418eSSumit Saxena 			return;
36072d1d418eSSumit Saxena 		delayed_dev_rmhs->handle = handle;
36082d1d418eSSumit Saxena 		delayed_dev_rmhs->iou_rc = iou_rc;
36092d1d418eSSumit Saxena 		TAILQ_INSERT_TAIL(&(sc->delayed_rmhs_list), delayed_dev_rmhs, list);
36102d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :DevRmHs: tr:handle(0x%04x) is postponed\n",
36112d1d418eSSumit Saxena 		    __func__, handle);
36122d1d418eSSumit Saxena 
36132d1d418eSSumit Saxena 
36142d1d418eSSumit Saxena 		return;
36152d1d418eSSumit Saxena 	}
36162d1d418eSSumit Saxena 	drv_cmd = &sc->dev_rmhs_cmds[cmd_idx];
36172d1d418eSSumit Saxena 
36182d1d418eSSumit Saxena issue_cmd:
36192d1d418eSSumit Saxena 	cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
36202d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT,
36212d1d418eSSumit Saxena 	    "%s :Issuing TR TM: for devhandle 0x%04x with dev_rmhs %d\n",
36222d1d418eSSumit Saxena 	    __func__, handle, cmd_idx);
36232d1d418eSSumit Saxena 
36242d1d418eSSumit Saxena 	memset(&tm_req, 0, sizeof(tm_req));
36252d1d418eSSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_PENDING) {
36262d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :Issue TM: Command is in use\n", __func__);
36272d1d418eSSumit Saxena 		goto out;
36282d1d418eSSumit Saxena 	}
36292d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_PENDING;
36302d1d418eSSumit Saxena 	drv_cmd->is_waiting = 0;
36312d1d418eSSumit Saxena 	drv_cmd->callback = mpi3mr_dev_rmhs_complete_tm;
36322d1d418eSSumit Saxena 	drv_cmd->dev_handle = handle;
36332d1d418eSSumit Saxena 	drv_cmd->iou_rc = iou_rc;
36342d1d418eSSumit Saxena 	tm_req.DevHandle = htole16(handle);
36352d1d418eSSumit Saxena 	tm_req.TaskType = MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
36362d1d418eSSumit Saxena 	tm_req.HostTag = htole16(drv_cmd->host_tag);
36372d1d418eSSumit Saxena 	tm_req.TaskHostTag = htole16(MPI3MR_HOSTTAG_INVALID);
36382d1d418eSSumit Saxena 	tm_req.Function = MPI3_FUNCTION_SCSI_TASK_MGMT;
36392d1d418eSSumit Saxena 
36402d1d418eSSumit Saxena 	mpi3mr_set_bit(handle, sc->removepend_bitmap);
36412d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &tm_req, sizeof(tm_req));
36422d1d418eSSumit Saxena 	if (retval) {
36432d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "%s :Issue DevRmHsTM: Admin Post failed\n",
36442d1d418eSSumit Saxena 		    __func__);
36452d1d418eSSumit Saxena 		goto out_failed;
36462d1d418eSSumit Saxena 	}
36472d1d418eSSumit Saxena out:
36482d1d418eSSumit Saxena 	return;
36492d1d418eSSumit Saxena out_failed:
36502d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
36512d1d418eSSumit Saxena 	drv_cmd->callback = NULL;
36522d1d418eSSumit Saxena 	drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
36532d1d418eSSumit Saxena 	drv_cmd->retry_count = 0;
36542d1d418eSSumit Saxena 	mpi3mr_clear_bit(cmd_idx, sc->devrem_bitmap);
36552d1d418eSSumit Saxena }
36562d1d418eSSumit Saxena 
36572d1d418eSSumit Saxena /**
36582d1d418eSSumit Saxena  * mpi3mr_complete_evt_ack - Event ack request completion
36592d1d418eSSumit Saxena  * @sc: Adapter instance reference
36602d1d418eSSumit Saxena  * @drv_cmd: Internal command tracker
36612d1d418eSSumit Saxena  *
36622d1d418eSSumit Saxena  * This is the completion handler for non blocking event
36632d1d418eSSumit Saxena  * acknowledgment sent to the firmware and this will issue any
36642d1d418eSSumit Saxena  * pending event acknowledgment request.
36652d1d418eSSumit Saxena  *
36662d1d418eSSumit Saxena  * Return: Nothing
36672d1d418eSSumit Saxena  */
36682d1d418eSSumit Saxena static void mpi3mr_complete_evt_ack(struct mpi3mr_softc *sc,
36692d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd)
36702d1d418eSSumit Saxena {
36712d1d418eSSumit Saxena 	U16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
36722d1d418eSSumit Saxena 	struct delayed_evtack_node *delayed_evtack = NULL;
36732d1d418eSSumit Saxena 
36742d1d418eSSumit Saxena 	if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) {
36752d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT,
36762d1d418eSSumit Saxena 		    "%s: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n", __func__,
36772d1d418eSSumit Saxena 		    (drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
36782d1d418eSSumit Saxena 		    drv_cmd->ioc_loginfo);
36792d1d418eSSumit Saxena 	}
36802d1d418eSSumit Saxena 
36812d1d418eSSumit Saxena 	if (!TAILQ_EMPTY(&sc->delayed_evtack_cmds_list)) {
36822d1d418eSSumit Saxena 		delayed_evtack = TAILQ_FIRST(&sc->delayed_evtack_cmds_list);
36832d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT,
36842d1d418eSSumit Saxena 		    "%s: processing delayed event ack for event %d\n",
36852d1d418eSSumit Saxena 		    __func__, delayed_evtack->event);
36862d1d418eSSumit Saxena 		mpi3mr_send_evt_ack(sc, delayed_evtack->event, drv_cmd,
36872d1d418eSSumit Saxena 		    delayed_evtack->event_ctx);
36882d1d418eSSumit Saxena 		TAILQ_REMOVE(&sc->delayed_evtack_cmds_list, delayed_evtack, list);
36892d1d418eSSumit Saxena 		free(delayed_evtack, M_MPI3MR);
36902d1d418eSSumit Saxena 		return;
36912d1d418eSSumit Saxena 	}
36922d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
36932d1d418eSSumit Saxena 	drv_cmd->callback = NULL;
36942d1d418eSSumit Saxena 	mpi3mr_clear_bit(cmd_idx, sc->evtack_cmds_bitmap);
36952d1d418eSSumit Saxena }
36962d1d418eSSumit Saxena 
36972d1d418eSSumit Saxena /**
36982d1d418eSSumit Saxena  * mpi3mr_send_evt_ack - Issue event acknwoledgment request
36992d1d418eSSumit Saxena  * @sc: Adapter instance reference
37002d1d418eSSumit Saxena  * @event: MPI3 event id
37012d1d418eSSumit Saxena  * @cmdparam: Internal command tracker
37022d1d418eSSumit Saxena  * @event_ctx: Event context
37032d1d418eSSumit Saxena  *
37042d1d418eSSumit Saxena  * Issues event acknowledgment request to the firmware if there
37052d1d418eSSumit Saxena  * is a free command to send the event ack else it to a pend
37062d1d418eSSumit Saxena  * list so that it will be processed on a completion of a prior
37072d1d418eSSumit Saxena  * event acknowledgment .
37082d1d418eSSumit Saxena  *
37092d1d418eSSumit Saxena  * Return: Nothing
37102d1d418eSSumit Saxena  */
37112d1d418eSSumit Saxena static void mpi3mr_send_evt_ack(struct mpi3mr_softc *sc, U8 event,
37122d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdparam, U32 event_ctx)
37132d1d418eSSumit Saxena {
37142d1d418eSSumit Saxena 	Mpi3EventAckRequest_t evtack_req;
37152d1d418eSSumit Saxena 	int retval = 0;
37162d1d418eSSumit Saxena 	U8 retrycount = 5;
37172d1d418eSSumit Saxena 	U16 cmd_idx = MPI3MR_NUM_EVTACKCMD;
37182d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd = cmdparam;
37192d1d418eSSumit Saxena 	struct delayed_evtack_node *delayed_evtack = NULL;
37202d1d418eSSumit Saxena 
37212d1d418eSSumit Saxena 	if (drv_cmd)
37222d1d418eSSumit Saxena 		goto issue_cmd;
37232d1d418eSSumit Saxena 	do {
37242d1d418eSSumit Saxena 		cmd_idx = mpi3mr_find_first_zero_bit(sc->evtack_cmds_bitmap,
37252d1d418eSSumit Saxena 		    MPI3MR_NUM_EVTACKCMD);
37262d1d418eSSumit Saxena 		if (cmd_idx < MPI3MR_NUM_EVTACKCMD) {
37272d1d418eSSumit Saxena 			if (!mpi3mr_test_and_set_bit(cmd_idx,
37282d1d418eSSumit Saxena 			    sc->evtack_cmds_bitmap))
37292d1d418eSSumit Saxena 				break;
37302d1d418eSSumit Saxena 			cmd_idx = MPI3MR_NUM_EVTACKCMD;
37312d1d418eSSumit Saxena 		}
37322d1d418eSSumit Saxena 	} while (retrycount--);
37332d1d418eSSumit Saxena 
37342d1d418eSSumit Saxena 	if (cmd_idx >= MPI3MR_NUM_EVTACKCMD) {
37352d1d418eSSumit Saxena 		delayed_evtack = malloc(sizeof(*delayed_evtack),M_MPI3MR,
37362d1d418eSSumit Saxena 		     M_ZERO | M_NOWAIT);
37372d1d418eSSumit Saxena 		if (!delayed_evtack)
37382d1d418eSSumit Saxena 			return;
37392d1d418eSSumit Saxena 		delayed_evtack->event = event;
37402d1d418eSSumit Saxena 		delayed_evtack->event_ctx = event_ctx;
37412d1d418eSSumit Saxena 		TAILQ_INSERT_TAIL(&(sc->delayed_evtack_cmds_list), delayed_evtack, list);
37422d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s : Event ack for event:%d is postponed\n",
37432d1d418eSSumit Saxena 		    __func__, event);
37442d1d418eSSumit Saxena 		return;
37452d1d418eSSumit Saxena 	}
37462d1d418eSSumit Saxena 	drv_cmd = &sc->evtack_cmds[cmd_idx];
37472d1d418eSSumit Saxena 
37482d1d418eSSumit Saxena issue_cmd:
37492d1d418eSSumit Saxena 	cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
37502d1d418eSSumit Saxena 
37512d1d418eSSumit Saxena 	memset(&evtack_req, 0, sizeof(evtack_req));
37522d1d418eSSumit Saxena 	if (drv_cmd->state & MPI3MR_CMD_PENDING) {
37532d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s: Command is in use\n", __func__);
37542d1d418eSSumit Saxena 		goto out;
37552d1d418eSSumit Saxena 	}
37562d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_PENDING;
37572d1d418eSSumit Saxena 	drv_cmd->is_waiting = 0;
37582d1d418eSSumit Saxena 	drv_cmd->callback = mpi3mr_complete_evt_ack;
37592d1d418eSSumit Saxena 	evtack_req.HostTag = htole16(drv_cmd->host_tag);
37602d1d418eSSumit Saxena 	evtack_req.Function = MPI3_FUNCTION_EVENT_ACK;
37612d1d418eSSumit Saxena 	evtack_req.Event = event;
37622d1d418eSSumit Saxena 	evtack_req.EventContext = htole32(event_ctx);
37632d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &evtack_req,
37642d1d418eSSumit Saxena 	    sizeof(evtack_req));
37652d1d418eSSumit Saxena 
37662d1d418eSSumit Saxena 	if (retval) {
37672d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "%s: Admin Post failed\n", __func__);
37682d1d418eSSumit Saxena 		goto out_failed;
37692d1d418eSSumit Saxena 	}
37702d1d418eSSumit Saxena out:
37712d1d418eSSumit Saxena 	return;
37722d1d418eSSumit Saxena out_failed:
37732d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
37742d1d418eSSumit Saxena 	drv_cmd->callback = NULL;
37752d1d418eSSumit Saxena 	mpi3mr_clear_bit(cmd_idx, sc->evtack_cmds_bitmap);
37762d1d418eSSumit Saxena }
37772d1d418eSSumit Saxena 
37782d1d418eSSumit Saxena /*
37792d1d418eSSumit Saxena  * mpi3mr_pcietopochg_evt_th - PCIETopologyChange evt tophalf
37802d1d418eSSumit Saxena  * @sc: Adapter instance reference
37812d1d418eSSumit Saxena  * @event_reply: Event data
37822d1d418eSSumit Saxena  *
37832d1d418eSSumit Saxena  * Checks for the reason code and based on that either block I/O
37842d1d418eSSumit Saxena  * to device, or unblock I/O to the device, or start the device
37852d1d418eSSumit Saxena  * removal handshake with reason as remove with the firmware for
37862d1d418eSSumit Saxena  * PCIe devices.
37872d1d418eSSumit Saxena  *
37882d1d418eSSumit Saxena  * Return: Nothing
37892d1d418eSSumit Saxena  */
37902d1d418eSSumit Saxena static void mpi3mr_pcietopochg_evt_th(struct mpi3mr_softc *sc,
37912d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
37922d1d418eSSumit Saxena {
37932d1d418eSSumit Saxena 	Mpi3EventDataPcieTopologyChangeList_t *topo_evt =
37942d1d418eSSumit Saxena 	    (Mpi3EventDataPcieTopologyChangeList_t *) event_reply->EventData;
37952d1d418eSSumit Saxena 	int i;
37962d1d418eSSumit Saxena 	U16 handle;
37972d1d418eSSumit Saxena 	U8 reason_code;
37982d1d418eSSumit Saxena 	struct mpi3mr_target *tgtdev = NULL;
37992d1d418eSSumit Saxena 
38002d1d418eSSumit Saxena 	for (i = 0; i < topo_evt->NumEntries; i++) {
38012d1d418eSSumit Saxena 		handle = le16toh(topo_evt->PortEntry[i].AttachedDevHandle);
38022d1d418eSSumit Saxena 		if (!handle)
38032d1d418eSSumit Saxena 			continue;
38042d1d418eSSumit Saxena 		reason_code = topo_evt->PortEntry[i].PortStatus;
38052d1d418eSSumit Saxena 		tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle);
38062d1d418eSSumit Saxena 		switch (reason_code) {
38072d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
38082d1d418eSSumit Saxena 			if (tgtdev) {
38092d1d418eSSumit Saxena 				tgtdev->dev_removed = 1;
38102d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 0;
38112d1d418eSSumit Saxena 				mpi3mr_atomic_set(&tgtdev->block_io, 0);
38122d1d418eSSumit Saxena 			}
38132d1d418eSSumit Saxena 			mpi3mr_dev_rmhs_send_tm(sc, handle, NULL,
38142d1d418eSSumit Saxena 			    MPI3_CTRL_OP_REMOVE_DEVICE);
38152d1d418eSSumit Saxena 			break;
38162d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
38172d1d418eSSumit Saxena 			if (tgtdev) {
38182d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 1;
38192d1d418eSSumit Saxena 				mpi3mr_atomic_inc(&tgtdev->block_io);
38202d1d418eSSumit Saxena 			}
38212d1d418eSSumit Saxena 			break;
38222d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_RESPONDING:
38232d1d418eSSumit Saxena 			if (tgtdev &&
38242d1d418eSSumit Saxena 			    tgtdev->dev_removedelay) {
38252d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 0;
38262d1d418eSSumit Saxena 				if (mpi3mr_atomic_read(&tgtdev->block_io) > 0)
38272d1d418eSSumit Saxena 					mpi3mr_atomic_dec(&tgtdev->block_io);
38282d1d418eSSumit Saxena 			}
38292d1d418eSSumit Saxena 			break;
38302d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
38312d1d418eSSumit Saxena 		default:
38322d1d418eSSumit Saxena 			break;
38332d1d418eSSumit Saxena 		}
38342d1d418eSSumit Saxena 	}
38352d1d418eSSumit Saxena }
38362d1d418eSSumit Saxena 
38372d1d418eSSumit Saxena /**
38382d1d418eSSumit Saxena  * mpi3mr_sastopochg_evt_th - SASTopologyChange evt tophalf
38392d1d418eSSumit Saxena  * @sc: Adapter instance reference
38402d1d418eSSumit Saxena  * @event_reply: Event data
38412d1d418eSSumit Saxena  *
38422d1d418eSSumit Saxena  * Checks for the reason code and based on that either block I/O
38432d1d418eSSumit Saxena  * to device, or unblock I/O to the device, or start the device
38442d1d418eSSumit Saxena  * removal handshake with reason as remove with the firmware for
38452d1d418eSSumit Saxena  * SAS/SATA devices.
38462d1d418eSSumit Saxena  *
38472d1d418eSSumit Saxena  * Return: Nothing
38482d1d418eSSumit Saxena  */
38492d1d418eSSumit Saxena static void mpi3mr_sastopochg_evt_th(struct mpi3mr_softc *sc,
38502d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
38512d1d418eSSumit Saxena {
38522d1d418eSSumit Saxena 	Mpi3EventDataSasTopologyChangeList_t *topo_evt =
38532d1d418eSSumit Saxena 	    (Mpi3EventDataSasTopologyChangeList_t *)event_reply->EventData;
38542d1d418eSSumit Saxena 	int i;
38552d1d418eSSumit Saxena 	U16 handle;
38562d1d418eSSumit Saxena 	U8 reason_code;
38572d1d418eSSumit Saxena 	struct mpi3mr_target *tgtdev = NULL;
38582d1d418eSSumit Saxena 
38592d1d418eSSumit Saxena 	for (i = 0; i < topo_evt->NumEntries; i++) {
38602d1d418eSSumit Saxena 		handle = le16toh(topo_evt->PhyEntry[i].AttachedDevHandle);
38612d1d418eSSumit Saxena 		if (!handle)
38622d1d418eSSumit Saxena 			continue;
38632d1d418eSSumit Saxena 		reason_code = topo_evt->PhyEntry[i].Status &
38642d1d418eSSumit Saxena 		    MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
38652d1d418eSSumit Saxena 		tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle);
38662d1d418eSSumit Saxena 		switch (reason_code) {
38672d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
38682d1d418eSSumit Saxena 			if (tgtdev) {
38692d1d418eSSumit Saxena 				tgtdev->dev_removed = 1;
38702d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 0;
38712d1d418eSSumit Saxena 				mpi3mr_atomic_set(&tgtdev->block_io, 0);
38722d1d418eSSumit Saxena 			}
38732d1d418eSSumit Saxena 			mpi3mr_dev_rmhs_send_tm(sc, handle, NULL,
38742d1d418eSSumit Saxena 			    MPI3_CTRL_OP_REMOVE_DEVICE);
38752d1d418eSSumit Saxena 			break;
38762d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING:
38772d1d418eSSumit Saxena 			if (tgtdev) {
38782d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 1;
38792d1d418eSSumit Saxena 				mpi3mr_atomic_inc(&tgtdev->block_io);
38802d1d418eSSumit Saxena 			}
38812d1d418eSSumit Saxena 			break;
38822d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
38832d1d418eSSumit Saxena 			if (tgtdev &&
38842d1d418eSSumit Saxena 			    tgtdev->dev_removedelay) {
38852d1d418eSSumit Saxena 				tgtdev->dev_removedelay = 0;
38862d1d418eSSumit Saxena 				if (mpi3mr_atomic_read(&tgtdev->block_io) > 0)
38872d1d418eSSumit Saxena 					mpi3mr_atomic_dec(&tgtdev->block_io);
38882d1d418eSSumit Saxena 			}
38892d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
38902d1d418eSSumit Saxena 		default:
38912d1d418eSSumit Saxena 			break;
38922d1d418eSSumit Saxena 		}
38932d1d418eSSumit Saxena 	}
38942d1d418eSSumit Saxena 
38952d1d418eSSumit Saxena }
38962d1d418eSSumit Saxena /**
38972d1d418eSSumit Saxena  * mpi3mr_devstatuschg_evt_th - DeviceStatusChange evt tophalf
38982d1d418eSSumit Saxena  * @sc: Adapter instance reference
38992d1d418eSSumit Saxena  * @event_reply: Event data
39002d1d418eSSumit Saxena  *
39012d1d418eSSumit Saxena  * Checks for the reason code and based on that either block I/O
39022d1d418eSSumit Saxena  * to device, or unblock I/O to the device, or start the device
39032d1d418eSSumit Saxena  * removal handshake with reason as remove/hide acknowledgment
39042d1d418eSSumit Saxena  * with the firmware.
39052d1d418eSSumit Saxena  *
39062d1d418eSSumit Saxena  * Return: Nothing
39072d1d418eSSumit Saxena  */
39082d1d418eSSumit Saxena static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_softc *sc,
39092d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
39102d1d418eSSumit Saxena {
39112d1d418eSSumit Saxena 	U16 dev_handle = 0;
39122d1d418eSSumit Saxena 	U8 ublock = 0, block = 0, hide = 0, uhide = 0, delete = 0, remove = 0;
39132d1d418eSSumit Saxena 	struct mpi3mr_target *tgtdev = NULL;
39142d1d418eSSumit Saxena 	Mpi3EventDataDeviceStatusChange_t *evtdata =
39152d1d418eSSumit Saxena 	    (Mpi3EventDataDeviceStatusChange_t *) event_reply->EventData;
39162d1d418eSSumit Saxena 
39172d1d418eSSumit Saxena 	dev_handle = le16toh(evtdata->DevHandle);
39182d1d418eSSumit Saxena 
39192d1d418eSSumit Saxena 	switch (evtdata->ReasonCode) {
39202d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT:
39212d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_STRT:
39222d1d418eSSumit Saxena 		block = 1;
39232d1d418eSSumit Saxena 		break;
39242d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_HIDDEN:
39252d1d418eSSumit Saxena 		delete = 1;
39262d1d418eSSumit Saxena 		hide = 1;
39272d1d418eSSumit Saxena 		break;
39282d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN:
39292d1d418eSSumit Saxena 		uhide = 1;
39302d1d418eSSumit Saxena 		break;
39312d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING:
39322d1d418eSSumit Saxena 		delete = 1;
39332d1d418eSSumit Saxena 		remove = 1;
39342d1d418eSSumit Saxena 		break;
39352d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_CMP:
39362d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_CMP:
39372d1d418eSSumit Saxena 		ublock = 1;
39382d1d418eSSumit Saxena 		break;
39392d1d418eSSumit Saxena 	default:
39402d1d418eSSumit Saxena 		break;
39412d1d418eSSumit Saxena 	}
39422d1d418eSSumit Saxena 
39432d1d418eSSumit Saxena 	tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle);
39442d1d418eSSumit Saxena 
39452d1d418eSSumit Saxena 	if (!tgtdev) {
39462d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "%s :target with dev_handle:0x%x not found\n",
39472d1d418eSSumit Saxena 		    __func__, dev_handle);
39482d1d418eSSumit Saxena 		return;
39492d1d418eSSumit Saxena 	}
39502d1d418eSSumit Saxena 
39512d1d418eSSumit Saxena 	if (block)
39522d1d418eSSumit Saxena 		mpi3mr_atomic_inc(&tgtdev->block_io);
39532d1d418eSSumit Saxena 
39542d1d418eSSumit Saxena 	if (hide)
39552d1d418eSSumit Saxena 		tgtdev->is_hidden = hide;
39562d1d418eSSumit Saxena 
39572d1d418eSSumit Saxena 	if (uhide) {
39582d1d418eSSumit Saxena 		tgtdev->is_hidden = 0;
39592d1d418eSSumit Saxena 		tgtdev->dev_removed = 0;
39602d1d418eSSumit Saxena 	}
39612d1d418eSSumit Saxena 
39622d1d418eSSumit Saxena 	if (delete)
39632d1d418eSSumit Saxena 		tgtdev->dev_removed = 1;
39642d1d418eSSumit Saxena 
39652d1d418eSSumit Saxena 	if (ublock) {
39662d1d418eSSumit Saxena 		if (mpi3mr_atomic_read(&tgtdev->block_io) > 0)
39672d1d418eSSumit Saxena 			mpi3mr_atomic_dec(&tgtdev->block_io);
39682d1d418eSSumit Saxena 	}
39692d1d418eSSumit Saxena 
39702d1d418eSSumit Saxena 	if (remove) {
39712d1d418eSSumit Saxena 		mpi3mr_dev_rmhs_send_tm(sc, dev_handle, NULL,
39722d1d418eSSumit Saxena 					MPI3_CTRL_OP_REMOVE_DEVICE);
39732d1d418eSSumit Saxena 	}
39742d1d418eSSumit Saxena 	if (hide)
39752d1d418eSSumit Saxena 		mpi3mr_dev_rmhs_send_tm(sc, dev_handle, NULL,
39762d1d418eSSumit Saxena 					MPI3_CTRL_OP_HIDDEN_ACK);
39772d1d418eSSumit Saxena }
39782d1d418eSSumit Saxena 
39792d1d418eSSumit Saxena /**
39802d1d418eSSumit Saxena  * mpi3mr_preparereset_evt_th - Prepareforreset evt tophalf
39812d1d418eSSumit Saxena  * @sc: Adapter instance reference
39822d1d418eSSumit Saxena  * @event_reply: Event data
39832d1d418eSSumit Saxena  *
39842d1d418eSSumit Saxena  * Blocks and unblocks host level I/O based on the reason code
39852d1d418eSSumit Saxena  *
39862d1d418eSSumit Saxena  * Return: Nothing
39872d1d418eSSumit Saxena  */
39882d1d418eSSumit Saxena static void mpi3mr_preparereset_evt_th(struct mpi3mr_softc *sc,
39892d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
39902d1d418eSSumit Saxena {
39912d1d418eSSumit Saxena 	Mpi3EventDataPrepareForReset_t *evtdata =
39922d1d418eSSumit Saxena 	    (Mpi3EventDataPrepareForReset_t *)event_reply->EventData;
39932d1d418eSSumit Saxena 
39942d1d418eSSumit Saxena 	if (evtdata->ReasonCode == MPI3_EVENT_PREPARE_RESET_RC_START) {
39952d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :Recieved PrepForReset Event with RC=START\n",
39962d1d418eSSumit Saxena 		    __func__);
39972d1d418eSSumit Saxena 		if (sc->prepare_for_reset)
39982d1d418eSSumit Saxena 			return;
39992d1d418eSSumit Saxena 		sc->prepare_for_reset = 1;
40002d1d418eSSumit Saxena 		sc->prepare_for_reset_timeout_counter = 0;
40012d1d418eSSumit Saxena 	} else if (evtdata->ReasonCode == MPI3_EVENT_PREPARE_RESET_RC_ABORT) {
40022d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :Recieved PrepForReset Event with RC=ABORT\n",
40032d1d418eSSumit Saxena 		    __func__);
40042d1d418eSSumit Saxena 		sc->prepare_for_reset = 0;
40052d1d418eSSumit Saxena 		sc->prepare_for_reset_timeout_counter = 0;
40062d1d418eSSumit Saxena 	}
40072d1d418eSSumit Saxena 	if ((event_reply->MsgFlags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK)
40082d1d418eSSumit Saxena 	    == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED)
40092d1d418eSSumit Saxena 		mpi3mr_send_evt_ack(sc, event_reply->Event, NULL,
40102d1d418eSSumit Saxena 		    le32toh(event_reply->EventContext));
40112d1d418eSSumit Saxena }
40122d1d418eSSumit Saxena 
40132d1d418eSSumit Saxena /**
40142d1d418eSSumit Saxena  * mpi3mr_energypackchg_evt_th - Energypackchange evt tophalf
40152d1d418eSSumit Saxena  * @sc: Adapter instance reference
40162d1d418eSSumit Saxena  * @event_reply: Event data
40172d1d418eSSumit Saxena  *
40182d1d418eSSumit Saxena  * Identifies the new shutdown timeout value and update.
40192d1d418eSSumit Saxena  *
40202d1d418eSSumit Saxena  * Return: Nothing
40212d1d418eSSumit Saxena  */
40222d1d418eSSumit Saxena static void mpi3mr_energypackchg_evt_th(struct mpi3mr_softc *sc,
40232d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
40242d1d418eSSumit Saxena {
40252d1d418eSSumit Saxena 	Mpi3EventDataEnergyPackChange_t *evtdata =
40262d1d418eSSumit Saxena 	    (Mpi3EventDataEnergyPackChange_t *)event_reply->EventData;
40272d1d418eSSumit Saxena 	U16 shutdown_timeout = le16toh(evtdata->ShutdownTimeout);
40282d1d418eSSumit Saxena 
40292d1d418eSSumit Saxena 	if (shutdown_timeout <= 0) {
40302d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
40312d1d418eSSumit Saxena 		    "%s :Invalid Shutdown Timeout received = %d\n",
40322d1d418eSSumit Saxena 		    __func__, shutdown_timeout);
40332d1d418eSSumit Saxena 		return;
40342d1d418eSSumit Saxena 	}
40352d1d418eSSumit Saxena 
40362d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT,
40372d1d418eSSumit Saxena 	    "%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n",
40382d1d418eSSumit Saxena 	    __func__, sc->facts.shutdown_timeout, shutdown_timeout);
40392d1d418eSSumit Saxena 	sc->facts.shutdown_timeout = shutdown_timeout;
40402d1d418eSSumit Saxena }
40412d1d418eSSumit Saxena 
40422d1d418eSSumit Saxena /**
40432d1d418eSSumit Saxena  * mpi3mr_cablemgmt_evt_th - Cable mgmt evt tophalf
40442d1d418eSSumit Saxena  * @sc: Adapter instance reference
40452d1d418eSSumit Saxena  * @event_reply: Event data
40462d1d418eSSumit Saxena  *
40472d1d418eSSumit Saxena  * Displays Cable manegemt event details.
40482d1d418eSSumit Saxena  *
40492d1d418eSSumit Saxena  * Return: Nothing
40502d1d418eSSumit Saxena  */
40512d1d418eSSumit Saxena static void mpi3mr_cablemgmt_evt_th(struct mpi3mr_softc *sc,
40522d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply)
40532d1d418eSSumit Saxena {
40542d1d418eSSumit Saxena 	Mpi3EventDataCableManagement_t *evtdata =
40552d1d418eSSumit Saxena 	    (Mpi3EventDataCableManagement_t *)event_reply->EventData;
40562d1d418eSSumit Saxena 
40572d1d418eSSumit Saxena 	switch (evtdata->Status) {
40582d1d418eSSumit Saxena 	case MPI3_EVENT_CABLE_MGMT_STATUS_INSUFFICIENT_POWER:
40592d1d418eSSumit Saxena 	{
40602d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "An active cable with ReceptacleID %d cannot be powered.\n"
40612d1d418eSSumit Saxena 		    "Devices connected to this cable are not detected.\n"
40622d1d418eSSumit Saxena 		    "This cable requires %d mW of power.\n",
40632d1d418eSSumit Saxena 		    evtdata->ReceptacleID,
40642d1d418eSSumit Saxena 		    le32toh(evtdata->ActiveCablePowerRequirement));
40652d1d418eSSumit Saxena 		break;
40662d1d418eSSumit Saxena 	}
40672d1d418eSSumit Saxena 	case MPI3_EVENT_CABLE_MGMT_STATUS_DEGRADED:
40682d1d418eSSumit Saxena 	{
40692d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "A cable with ReceptacleID %d is not running at optimal speed\n",
40702d1d418eSSumit Saxena 		    evtdata->ReceptacleID);
40712d1d418eSSumit Saxena 		break;
40722d1d418eSSumit Saxena 	}
40732d1d418eSSumit Saxena 	default:
40742d1d418eSSumit Saxena 		break;
40752d1d418eSSumit Saxena 	}
40762d1d418eSSumit Saxena }
40772d1d418eSSumit Saxena 
40782d1d418eSSumit Saxena /**
40792d1d418eSSumit Saxena  * mpi3mr_process_events - Event's toph-half handler
40802d1d418eSSumit Saxena  * @sc: Adapter instance reference
40812d1d418eSSumit Saxena  * @event_reply: Event data
40822d1d418eSSumit Saxena  *
40832d1d418eSSumit Saxena  * Top half of event processing.
40842d1d418eSSumit Saxena  *
40852d1d418eSSumit Saxena  * Return: Nothing
40862d1d418eSSumit Saxena  */
40872d1d418eSSumit Saxena static void mpi3mr_process_events(struct mpi3mr_softc *sc,
40882d1d418eSSumit Saxena     uintptr_t data, Mpi3EventNotificationReply_t *event_reply)
40892d1d418eSSumit Saxena {
40902d1d418eSSumit Saxena 	U16 evt_type;
40912d1d418eSSumit Saxena 	bool ack_req = 0, process_evt_bh = 0;
40922d1d418eSSumit Saxena 	struct mpi3mr_fw_event_work *fw_event;
40932d1d418eSSumit Saxena 	U16 sz;
40942d1d418eSSumit Saxena 
40952d1d418eSSumit Saxena 	if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN)
40962d1d418eSSumit Saxena 		goto out;
40972d1d418eSSumit Saxena 
40982d1d418eSSumit Saxena 	if ((event_reply->MsgFlags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK)
40992d1d418eSSumit Saxena 	    == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED)
41002d1d418eSSumit Saxena 		ack_req = 1;
41012d1d418eSSumit Saxena 
41022d1d418eSSumit Saxena 	evt_type = event_reply->Event;
41032d1d418eSSumit Saxena 
41042d1d418eSSumit Saxena 	switch (evt_type) {
41052d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_ADDED:
41062d1d418eSSumit Saxena 	{
41072d1d418eSSumit Saxena 		Mpi3DevicePage0_t *dev_pg0 =
41082d1d418eSSumit Saxena 			(Mpi3DevicePage0_t *) event_reply->EventData;
41092d1d418eSSumit Saxena 		if (mpi3mr_create_device(sc, dev_pg0))
41102d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
41112d1d418eSSumit Saxena 			"%s :Failed to add device in the device add event\n",
41122d1d418eSSumit Saxena 			__func__);
41132d1d418eSSumit Saxena 		else
41142d1d418eSSumit Saxena 			process_evt_bh = 1;
41152d1d418eSSumit Saxena 		break;
41162d1d418eSSumit Saxena 	}
41172d1d418eSSumit Saxena 
41182d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
41192d1d418eSSumit Saxena 	{
41202d1d418eSSumit Saxena 		process_evt_bh = 1;
41212d1d418eSSumit Saxena 		mpi3mr_devstatuschg_evt_th(sc, event_reply);
41222d1d418eSSumit Saxena 		break;
41232d1d418eSSumit Saxena 	}
41242d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
41252d1d418eSSumit Saxena 	{
41262d1d418eSSumit Saxena 		process_evt_bh = 1;
41272d1d418eSSumit Saxena 		mpi3mr_sastopochg_evt_th(sc, event_reply);
41282d1d418eSSumit Saxena 		break;
41292d1d418eSSumit Saxena 	}
41302d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
41312d1d418eSSumit Saxena 	{
41322d1d418eSSumit Saxena 		process_evt_bh = 1;
41332d1d418eSSumit Saxena 		mpi3mr_pcietopochg_evt_th(sc, event_reply);
41342d1d418eSSumit Saxena 		break;
41352d1d418eSSumit Saxena 	}
41362d1d418eSSumit Saxena 	case MPI3_EVENT_PREPARE_FOR_RESET:
41372d1d418eSSumit Saxena 	{
41382d1d418eSSumit Saxena 		mpi3mr_preparereset_evt_th(sc, event_reply);
41392d1d418eSSumit Saxena 		ack_req = 0;
41402d1d418eSSumit Saxena 		break;
41412d1d418eSSumit Saxena 	}
41422d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
41432d1d418eSSumit Saxena 	case MPI3_EVENT_LOG_DATA:
41442d1d418eSSumit Saxena 	{
41452d1d418eSSumit Saxena 		process_evt_bh = 1;
41462d1d418eSSumit Saxena 		break;
41472d1d418eSSumit Saxena 	}
41482d1d418eSSumit Saxena 	case MPI3_EVENT_ENERGY_PACK_CHANGE:
41492d1d418eSSumit Saxena 	{
41502d1d418eSSumit Saxena 		mpi3mr_energypackchg_evt_th(sc, event_reply);
41512d1d418eSSumit Saxena 		break;
41522d1d418eSSumit Saxena 	}
41532d1d418eSSumit Saxena 	case MPI3_EVENT_CABLE_MGMT:
41542d1d418eSSumit Saxena 	{
41552d1d418eSSumit Saxena 		mpi3mr_cablemgmt_evt_th(sc, event_reply);
41562d1d418eSSumit Saxena 		break;
41572d1d418eSSumit Saxena 	}
41582d1d418eSSumit Saxena 
41592d1d418eSSumit Saxena 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
41602d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_DISCOVERY:
41612d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
41622d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
41632d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_ENUMERATION:
41642d1d418eSSumit Saxena 		break;
41652d1d418eSSumit Saxena 	default:
41662d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "%s :Event 0x%02x is not handled by driver\n",
41672d1d418eSSumit Saxena 		    __func__, evt_type);
41682d1d418eSSumit Saxena 		break;
41692d1d418eSSumit Saxena 	}
41702d1d418eSSumit Saxena 
41712d1d418eSSumit Saxena 	if (process_evt_bh || ack_req) {
41722d1d418eSSumit Saxena 		fw_event = malloc(sizeof(struct mpi3mr_fw_event_work), M_MPI3MR,
41732d1d418eSSumit Saxena 		     M_ZERO|M_NOWAIT);
41742d1d418eSSumit Saxena 
41752d1d418eSSumit Saxena 		if (!fw_event) {
41762d1d418eSSumit Saxena 			printf("%s: allocate failed for fw_event\n", __func__);
41772d1d418eSSumit Saxena 			return;
41782d1d418eSSumit Saxena 		}
41792d1d418eSSumit Saxena 
41802d1d418eSSumit Saxena 		sz = le16toh(event_reply->EventDataLength) * 4;
41812d1d418eSSumit Saxena 		fw_event->event_data = malloc(sz, M_MPI3MR, M_ZERO|M_NOWAIT);
41822d1d418eSSumit Saxena 
41832d1d418eSSumit Saxena 		if (!fw_event->event_data) {
41842d1d418eSSumit Saxena 			printf("%s: allocate failed for event_data\n", __func__);
41852d1d418eSSumit Saxena 			free(fw_event, M_MPI3MR);
41862d1d418eSSumit Saxena 			return;
41872d1d418eSSumit Saxena 		}
41882d1d418eSSumit Saxena 
41892d1d418eSSumit Saxena 		bcopy(event_reply->EventData, fw_event->event_data, sz);
41902d1d418eSSumit Saxena 		fw_event->event = event_reply->Event;
41912d1d418eSSumit Saxena 		if ((event_reply->Event == MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
41922d1d418eSSumit Saxena 		    event_reply->Event == MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST ||
41932d1d418eSSumit Saxena 		    event_reply->Event == MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE ) &&
41942d1d418eSSumit Saxena 		    sc->track_mapping_events)
41952d1d418eSSumit Saxena 			sc->pending_map_events++;
41962d1d418eSSumit Saxena 
41972d1d418eSSumit Saxena 		/*
41982d1d418eSSumit Saxena 		 * Events should be processed after Port enable is completed.
41992d1d418eSSumit Saxena 		 */
42002d1d418eSSumit Saxena 		if ((event_reply->Event == MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
42012d1d418eSSumit Saxena 		    event_reply->Event == MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST ) &&
42022d1d418eSSumit Saxena 		    !(sc->mpi3mr_flags & MPI3MR_FLAGS_PORT_ENABLE_DONE))
42032d1d418eSSumit Saxena 			mpi3mr_startup_increment(sc->cam_sc);
42042d1d418eSSumit Saxena 
42052d1d418eSSumit Saxena 		fw_event->send_ack = ack_req;
42062d1d418eSSumit Saxena 		fw_event->event_context = le32toh(event_reply->EventContext);
42072d1d418eSSumit Saxena 		fw_event->event_data_size = sz;
42082d1d418eSSumit Saxena 		fw_event->process_event = process_evt_bh;
42092d1d418eSSumit Saxena 
42102d1d418eSSumit Saxena 		mtx_lock(&sc->fwevt_lock);
42112d1d418eSSumit Saxena 		TAILQ_INSERT_TAIL(&sc->cam_sc->ev_queue, fw_event, ev_link);
42122d1d418eSSumit Saxena 		taskqueue_enqueue(sc->cam_sc->ev_tq, &sc->cam_sc->ev_task);
42132d1d418eSSumit Saxena 		mtx_unlock(&sc->fwevt_lock);
42142d1d418eSSumit Saxena 
42152d1d418eSSumit Saxena 	}
42162d1d418eSSumit Saxena out:
42172d1d418eSSumit Saxena 	return;
42182d1d418eSSumit Saxena }
42192d1d418eSSumit Saxena 
42202d1d418eSSumit Saxena static void mpi3mr_handle_events(struct mpi3mr_softc *sc, uintptr_t data,
42212d1d418eSSumit Saxena     Mpi3DefaultReply_t *def_reply)
42222d1d418eSSumit Saxena {
42232d1d418eSSumit Saxena 	Mpi3EventNotificationReply_t *event_reply =
42242d1d418eSSumit Saxena 		(Mpi3EventNotificationReply_t *)def_reply;
42252d1d418eSSumit Saxena 
42262d1d418eSSumit Saxena 	sc->change_count = event_reply->IOCChangeCount;
42272d1d418eSSumit Saxena 	mpi3mr_display_event_data(sc, event_reply);
42282d1d418eSSumit Saxena 
42292d1d418eSSumit Saxena 	mpi3mr_process_events(sc, data, event_reply);
42302d1d418eSSumit Saxena }
42312d1d418eSSumit Saxena 
42322d1d418eSSumit Saxena static void mpi3mr_process_admin_reply_desc(struct mpi3mr_softc *sc,
42332d1d418eSSumit Saxena     Mpi3DefaultReplyDescriptor_t *reply_desc, U64 *reply_dma)
42342d1d418eSSumit Saxena {
42352d1d418eSSumit Saxena 	U16 reply_desc_type, host_tag = 0, idx;
42362d1d418eSSumit Saxena 	U16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
42372d1d418eSSumit Saxena 	U32 ioc_loginfo = 0;
42382d1d418eSSumit Saxena 	Mpi3StatusReplyDescriptor_t *status_desc;
42392d1d418eSSumit Saxena 	Mpi3AddressReplyDescriptor_t *addr_desc;
42402d1d418eSSumit Saxena 	Mpi3SuccessReplyDescriptor_t *success_desc;
42412d1d418eSSumit Saxena 	Mpi3DefaultReply_t *def_reply = NULL;
42422d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdptr = NULL;
42432d1d418eSSumit Saxena 	Mpi3SCSIIOReply_t *scsi_reply;
42442d1d418eSSumit Saxena 	U8 *sense_buf = NULL;
42452d1d418eSSumit Saxena 
42462d1d418eSSumit Saxena 	*reply_dma = 0;
42472d1d418eSSumit Saxena 	reply_desc_type = reply_desc->ReplyFlags &
42482d1d418eSSumit Saxena 			    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
42492d1d418eSSumit Saxena 	switch (reply_desc_type) {
42502d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
42512d1d418eSSumit Saxena 		status_desc = (Mpi3StatusReplyDescriptor_t *)reply_desc;
42522d1d418eSSumit Saxena 		host_tag = status_desc->HostTag;
42532d1d418eSSumit Saxena 		ioc_status = status_desc->IOCStatus;
42542d1d418eSSumit Saxena 		if (ioc_status &
42552d1d418eSSumit Saxena 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
42562d1d418eSSumit Saxena 			ioc_loginfo = status_desc->IOCLogInfo;
42572d1d418eSSumit Saxena 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
42582d1d418eSSumit Saxena 		break;
42592d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
42602d1d418eSSumit Saxena 		addr_desc = (Mpi3AddressReplyDescriptor_t *)reply_desc;
42612d1d418eSSumit Saxena 		*reply_dma = addr_desc->ReplyFrameAddress;
42622d1d418eSSumit Saxena 		def_reply = mpi3mr_get_reply_virt_addr(sc, *reply_dma);
42632d1d418eSSumit Saxena 		if (def_reply == NULL)
42642d1d418eSSumit Saxena 			goto out;
42652d1d418eSSumit Saxena 		host_tag = def_reply->HostTag;
42662d1d418eSSumit Saxena 		ioc_status = def_reply->IOCStatus;
42672d1d418eSSumit Saxena 		if (ioc_status &
42682d1d418eSSumit Saxena 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
42692d1d418eSSumit Saxena 			ioc_loginfo = def_reply->IOCLogInfo;
42702d1d418eSSumit Saxena 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
42712d1d418eSSumit Saxena 		if (def_reply->Function == MPI3_FUNCTION_SCSI_IO) {
42722d1d418eSSumit Saxena 			scsi_reply = (Mpi3SCSIIOReply_t *)def_reply;
42732d1d418eSSumit Saxena 			sense_buf = mpi3mr_get_sensebuf_virt_addr(sc,
42742d1d418eSSumit Saxena 			    scsi_reply->SenseDataBufferAddress);
42752d1d418eSSumit Saxena 		}
42762d1d418eSSumit Saxena 		break;
42772d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
42782d1d418eSSumit Saxena 		success_desc = (Mpi3SuccessReplyDescriptor_t *)reply_desc;
42792d1d418eSSumit Saxena 		host_tag = success_desc->HostTag;
42802d1d418eSSumit Saxena 		break;
42812d1d418eSSumit Saxena 	default:
42822d1d418eSSumit Saxena 		break;
42832d1d418eSSumit Saxena 	}
42842d1d418eSSumit Saxena 	switch (host_tag) {
42852d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_INITCMDS:
42862d1d418eSSumit Saxena 		cmdptr = &sc->init_cmds;
42872d1d418eSSumit Saxena 		break;
42882d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_IOCTLCMDS:
42892d1d418eSSumit Saxena 		cmdptr = &sc->ioctl_cmds;
42902d1d418eSSumit Saxena 		break;
42912d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_TMS:
42922d1d418eSSumit Saxena 		cmdptr = &sc->host_tm_cmds;
42932d1d418eSSumit Saxena 		wakeup((void *)&sc->tm_chan);
42942d1d418eSSumit Saxena 		break;
42952d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_PELABORT:
42962d1d418eSSumit Saxena 		cmdptr = &sc->pel_abort_cmd;
42972d1d418eSSumit Saxena 		break;
42982d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_PELWAIT:
42992d1d418eSSumit Saxena 		cmdptr = &sc->pel_cmds;
43002d1d418eSSumit Saxena 		break;
43012d1d418eSSumit Saxena 	case MPI3MR_HOSTTAG_INVALID:
43022d1d418eSSumit Saxena 		if (def_reply && def_reply->Function ==
43032d1d418eSSumit Saxena 		    MPI3_FUNCTION_EVENT_NOTIFICATION)
43042d1d418eSSumit Saxena 			mpi3mr_handle_events(sc, *reply_dma ,def_reply);
43052d1d418eSSumit Saxena 	default:
43062d1d418eSSumit Saxena 		break;
43072d1d418eSSumit Saxena 	}
43082d1d418eSSumit Saxena 
43092d1d418eSSumit Saxena 	if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN &&
43102d1d418eSSumit Saxena 	    host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX ) {
43112d1d418eSSumit Saxena 		idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
43122d1d418eSSumit Saxena 		cmdptr = &sc->dev_rmhs_cmds[idx];
43132d1d418eSSumit Saxena 	}
43142d1d418eSSumit Saxena 
43152d1d418eSSumit Saxena 	if (host_tag >= MPI3MR_HOSTTAG_EVTACKCMD_MIN &&
43162d1d418eSSumit Saxena 	    host_tag <= MPI3MR_HOSTTAG_EVTACKCMD_MAX) {
43172d1d418eSSumit Saxena 		idx = host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN;
43182d1d418eSSumit Saxena 		cmdptr = &sc->evtack_cmds[idx];
43192d1d418eSSumit Saxena 	}
43202d1d418eSSumit Saxena 
43212d1d418eSSumit Saxena 	if (cmdptr) {
43222d1d418eSSumit Saxena 		if (cmdptr->state & MPI3MR_CMD_PENDING) {
43232d1d418eSSumit Saxena 			cmdptr->state |= MPI3MR_CMD_COMPLETE;
43242d1d418eSSumit Saxena 			cmdptr->ioc_loginfo = ioc_loginfo;
43252d1d418eSSumit Saxena 			cmdptr->ioc_status = ioc_status;
43262d1d418eSSumit Saxena 			cmdptr->state &= ~MPI3MR_CMD_PENDING;
43272d1d418eSSumit Saxena 			if (def_reply) {
43282d1d418eSSumit Saxena 				cmdptr->state |= MPI3MR_CMD_REPLYVALID;
43292d1d418eSSumit Saxena 				memcpy((U8 *)cmdptr->reply, (U8 *)def_reply,
43302d1d418eSSumit Saxena 				    sc->reply_sz);
43312d1d418eSSumit Saxena 			}
43322d1d418eSSumit Saxena 			if (sense_buf && cmdptr->sensebuf) {
43332d1d418eSSumit Saxena 				cmdptr->is_senseprst = 1;
43342d1d418eSSumit Saxena 				memcpy(cmdptr->sensebuf, sense_buf,
43352d1d418eSSumit Saxena 				    MPI3MR_SENSEBUF_SZ);
43362d1d418eSSumit Saxena 			}
43372d1d418eSSumit Saxena 			if (cmdptr->is_waiting) {
43382d1d418eSSumit Saxena 				complete(&cmdptr->completion);
43392d1d418eSSumit Saxena 				cmdptr->is_waiting = 0;
43402d1d418eSSumit Saxena 			} else if (cmdptr->callback)
43412d1d418eSSumit Saxena 				cmdptr->callback(sc, cmdptr);
43422d1d418eSSumit Saxena 		}
43432d1d418eSSumit Saxena 	}
43442d1d418eSSumit Saxena out:
43452d1d418eSSumit Saxena 	if (sense_buf != NULL)
43462d1d418eSSumit Saxena 		mpi3mr_repost_sense_buf(sc,
43472d1d418eSSumit Saxena 		    scsi_reply->SenseDataBufferAddress);
43482d1d418eSSumit Saxena 	return;
43492d1d418eSSumit Saxena }
43502d1d418eSSumit Saxena 
43512d1d418eSSumit Saxena /*
43522d1d418eSSumit Saxena  * mpi3mr_complete_admin_cmd:	ISR routine for admin commands
43532d1d418eSSumit Saxena  * @sc:				Adapter's soft instance
43542d1d418eSSumit Saxena  *
43552d1d418eSSumit Saxena  * This function processes admin command completions.
43562d1d418eSSumit Saxena  */
43572d1d418eSSumit Saxena static int mpi3mr_complete_admin_cmd(struct mpi3mr_softc *sc)
43582d1d418eSSumit Saxena {
43592d1d418eSSumit Saxena 	U32 exp_phase = sc->admin_reply_ephase;
43602d1d418eSSumit Saxena 	U32 adm_reply_ci = sc->admin_reply_ci;
43612d1d418eSSumit Saxena 	U32 num_adm_reply = 0;
43622d1d418eSSumit Saxena 	U64 reply_dma = 0;
43632d1d418eSSumit Saxena 	Mpi3DefaultReplyDescriptor_t *reply_desc;
43642d1d418eSSumit Saxena 
43652d1d418eSSumit Saxena 	mtx_lock_spin(&sc->admin_reply_lock);
43662d1d418eSSumit Saxena 	if (sc->admin_in_use == false) {
43672d1d418eSSumit Saxena 		sc->admin_in_use = true;
43682d1d418eSSumit Saxena 		mtx_unlock_spin(&sc->admin_reply_lock);
43692d1d418eSSumit Saxena 	} else {
43702d1d418eSSumit Saxena 		mtx_unlock_spin(&sc->admin_reply_lock);
43712d1d418eSSumit Saxena 		return 0;
43722d1d418eSSumit Saxena 	}
43732d1d418eSSumit Saxena 
43742d1d418eSSumit Saxena 	reply_desc = (Mpi3DefaultReplyDescriptor_t *)sc->admin_reply +
43752d1d418eSSumit Saxena 		adm_reply_ci;
43762d1d418eSSumit Saxena 
43772d1d418eSSumit Saxena 	if ((reply_desc->ReplyFlags &
43782d1d418eSSumit Saxena 	     MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
43792d1d418eSSumit Saxena 		mtx_lock_spin(&sc->admin_reply_lock);
43802d1d418eSSumit Saxena 		sc->admin_in_use = false;
43812d1d418eSSumit Saxena 		mtx_unlock_spin(&sc->admin_reply_lock);
43822d1d418eSSumit Saxena 		return 0;
43832d1d418eSSumit Saxena 	}
43842d1d418eSSumit Saxena 
43852d1d418eSSumit Saxena 	do {
43862d1d418eSSumit Saxena 		sc->admin_req_ci = reply_desc->RequestQueueCI;
43872d1d418eSSumit Saxena 		mpi3mr_process_admin_reply_desc(sc, reply_desc, &reply_dma);
43882d1d418eSSumit Saxena 		if (reply_dma)
43892d1d418eSSumit Saxena 			mpi3mr_repost_reply_buf(sc, reply_dma);
43902d1d418eSSumit Saxena 		num_adm_reply++;
43912d1d418eSSumit Saxena 		if (++adm_reply_ci == sc->num_admin_replies) {
43922d1d418eSSumit Saxena 			adm_reply_ci = 0;
43932d1d418eSSumit Saxena 			exp_phase ^= 1;
43942d1d418eSSumit Saxena 		}
43952d1d418eSSumit Saxena 		reply_desc =
43962d1d418eSSumit Saxena 			(Mpi3DefaultReplyDescriptor_t *)sc->admin_reply +
43972d1d418eSSumit Saxena 			    adm_reply_ci;
43982d1d418eSSumit Saxena 		if ((reply_desc->ReplyFlags &
43992d1d418eSSumit Saxena 		     MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
44002d1d418eSSumit Saxena 			break;
44012d1d418eSSumit Saxena 	} while (1);
44022d1d418eSSumit Saxena 
44032d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REPLY_Q_CI_OFFSET, adm_reply_ci);
44042d1d418eSSumit Saxena 	sc->admin_reply_ci = adm_reply_ci;
44052d1d418eSSumit Saxena 	sc->admin_reply_ephase = exp_phase;
44062d1d418eSSumit Saxena 	mtx_lock_spin(&sc->admin_reply_lock);
44072d1d418eSSumit Saxena 	sc->admin_in_use = false;
44082d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->admin_reply_lock);
44092d1d418eSSumit Saxena 	return num_adm_reply;
44102d1d418eSSumit Saxena }
44112d1d418eSSumit Saxena 
44122d1d418eSSumit Saxena static void
44132d1d418eSSumit Saxena mpi3mr_cmd_done(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cmd)
44142d1d418eSSumit Saxena {
44152d1d418eSSumit Saxena 	mpi3mr_unmap_request(sc, cmd);
44162d1d418eSSumit Saxena 
44172d1d418eSSumit Saxena 	mtx_lock(&sc->mpi3mr_mtx);
44182d1d418eSSumit Saxena 	if (cmd->callout_owner) {
44192d1d418eSSumit Saxena 		callout_stop(&cmd->callout);
44202d1d418eSSumit Saxena 		cmd->callout_owner = false;
44212d1d418eSSumit Saxena 	}
44222d1d418eSSumit Saxena 
44232d1d418eSSumit Saxena 	if (sc->unrecoverable)
44242d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(cmd->ccb, CAM_DEV_NOT_THERE);
44252d1d418eSSumit Saxena 
44262d1d418eSSumit Saxena 	xpt_done(cmd->ccb);
44272d1d418eSSumit Saxena 	cmd->ccb = NULL;
44282d1d418eSSumit Saxena 	mtx_unlock(&sc->mpi3mr_mtx);
44292d1d418eSSumit Saxena 	mpi3mr_release_command(cmd);
44302d1d418eSSumit Saxena }
44312d1d418eSSumit Saxena 
44322d1d418eSSumit Saxena void mpi3mr_process_op_reply_desc(struct mpi3mr_softc *sc,
44332d1d418eSSumit Saxena     Mpi3DefaultReplyDescriptor_t *reply_desc, U64 *reply_dma)
44342d1d418eSSumit Saxena {
44352d1d418eSSumit Saxena 	U16 reply_desc_type, host_tag = 0;
44362d1d418eSSumit Saxena 	U16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
44372d1d418eSSumit Saxena 	U32 ioc_loginfo = 0;
44382d1d418eSSumit Saxena 	Mpi3StatusReplyDescriptor_t *status_desc = NULL;
44392d1d418eSSumit Saxena 	Mpi3AddressReplyDescriptor_t *addr_desc = NULL;
44402d1d418eSSumit Saxena 	Mpi3SuccessReplyDescriptor_t *success_desc = NULL;
44412d1d418eSSumit Saxena 	Mpi3SCSIIOReply_t *scsi_reply = NULL;
44422d1d418eSSumit Saxena 	U8 *sense_buf = NULL;
44432d1d418eSSumit Saxena 	U8 scsi_state = 0, scsi_status = 0, sense_state = 0;
44442d1d418eSSumit Saxena 	U32 xfer_count = 0, sense_count =0, resp_data = 0;
44452d1d418eSSumit Saxena 	struct mpi3mr_cmd *cm = NULL;
44462d1d418eSSumit Saxena 	union ccb *ccb;
44472d1d418eSSumit Saxena 	struct ccb_scsiio *csio;
44482d1d418eSSumit Saxena 	struct mpi3mr_cam_softc *cam_sc;
44492d1d418eSSumit Saxena 	U32 target_id;
44502d1d418eSSumit Saxena 	U8 *scsi_cdb;
44512d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
44522d1d418eSSumit Saxena 	U32 ioc_pend_data_len = 0, tg_pend_data_len = 0, data_len_blks = 0;
44532d1d418eSSumit Saxena 	struct mpi3mr_throttle_group_info *tg = NULL;
44542d1d418eSSumit Saxena 	U8 throttle_enabled_dev = 0;
44552d1d418eSSumit Saxena 	static int ratelimit;
44562d1d418eSSumit Saxena 
44572d1d418eSSumit Saxena 	*reply_dma = 0;
44582d1d418eSSumit Saxena 	reply_desc_type = reply_desc->ReplyFlags &
44592d1d418eSSumit Saxena 			    MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
44602d1d418eSSumit Saxena 	switch (reply_desc_type) {
44612d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
44622d1d418eSSumit Saxena 		status_desc = (Mpi3StatusReplyDescriptor_t *)reply_desc;
44632d1d418eSSumit Saxena 		host_tag = status_desc->HostTag;
44642d1d418eSSumit Saxena 		ioc_status = status_desc->IOCStatus;
44652d1d418eSSumit Saxena 		if (ioc_status &
44662d1d418eSSumit Saxena 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
44672d1d418eSSumit Saxena 			ioc_loginfo = status_desc->IOCLogInfo;
44682d1d418eSSumit Saxena 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
44692d1d418eSSumit Saxena 		break;
44702d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
44712d1d418eSSumit Saxena 		addr_desc = (Mpi3AddressReplyDescriptor_t *)reply_desc;
44722d1d418eSSumit Saxena 		*reply_dma = addr_desc->ReplyFrameAddress;
44732d1d418eSSumit Saxena 		scsi_reply = mpi3mr_get_reply_virt_addr(sc,
44742d1d418eSSumit Saxena 		    *reply_dma);
44752d1d418eSSumit Saxena 		if (scsi_reply == NULL) {
44762d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "scsi_reply is NULL, "
44772d1d418eSSumit Saxena 			    "this shouldn't happen, reply_desc: %p\n",
44782d1d418eSSumit Saxena 			    reply_desc);
44792d1d418eSSumit Saxena 			goto out;
44802d1d418eSSumit Saxena 		}
44812d1d418eSSumit Saxena 
44822d1d418eSSumit Saxena 		host_tag = scsi_reply->HostTag;
44832d1d418eSSumit Saxena 		ioc_status = scsi_reply->IOCStatus;
44842d1d418eSSumit Saxena 		scsi_status = scsi_reply->SCSIStatus;
44852d1d418eSSumit Saxena 		scsi_state = scsi_reply->SCSIState;
44862d1d418eSSumit Saxena 		sense_state = (scsi_state & MPI3_SCSI_STATE_SENSE_MASK);
44872d1d418eSSumit Saxena 		xfer_count = scsi_reply->TransferCount;
44882d1d418eSSumit Saxena 		sense_count = scsi_reply->SenseCount;
44892d1d418eSSumit Saxena 		resp_data = scsi_reply->ResponseData;
44902d1d418eSSumit Saxena 		sense_buf = mpi3mr_get_sensebuf_virt_addr(sc,
44912d1d418eSSumit Saxena 		    scsi_reply->SenseDataBufferAddress);
44922d1d418eSSumit Saxena 		if (ioc_status &
44932d1d418eSSumit Saxena 		    MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
44942d1d418eSSumit Saxena 			ioc_loginfo = scsi_reply->IOCLogInfo;
44952d1d418eSSumit Saxena 		ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
44962d1d418eSSumit Saxena 		if (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY)
44972d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Ran out of sense buffers\n");
44982d1d418eSSumit Saxena 
44992d1d418eSSumit Saxena 		break;
45002d1d418eSSumit Saxena 	case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
45012d1d418eSSumit Saxena 		success_desc = (Mpi3SuccessReplyDescriptor_t *)reply_desc;
45022d1d418eSSumit Saxena 		host_tag = success_desc->HostTag;
45032d1d418eSSumit Saxena 
45042d1d418eSSumit Saxena 	default:
45052d1d418eSSumit Saxena 		break;
45062d1d418eSSumit Saxena 	}
45072d1d418eSSumit Saxena 
45082d1d418eSSumit Saxena 	cm = sc->cmd_list[host_tag];
45092d1d418eSSumit Saxena 
45102d1d418eSSumit Saxena 	if (cm->state == MPI3MR_CMD_STATE_FREE)
45112d1d418eSSumit Saxena 		goto out;
45122d1d418eSSumit Saxena 
45132d1d418eSSumit Saxena 	cam_sc = sc->cam_sc;
45142d1d418eSSumit Saxena 	ccb = cm->ccb;
45152d1d418eSSumit Saxena 	csio = &ccb->csio;
45162d1d418eSSumit Saxena 	target_id = csio->ccb_h.target_id;
45172d1d418eSSumit Saxena 
45182d1d418eSSumit Saxena 	scsi_cdb = scsiio_cdb_ptr(csio);
45192d1d418eSSumit Saxena 
45202d1d418eSSumit Saxena 	target = mpi3mr_find_target_by_per_id(cam_sc, target_id);
45212d1d418eSSumit Saxena 	if (sc->iot_enable) {
45222d1d418eSSumit Saxena 		data_len_blks = csio->dxfer_len >> 9;
45232d1d418eSSumit Saxena 
45242d1d418eSSumit Saxena 		if (target) {
45252d1d418eSSumit Saxena 			tg = target->throttle_group;
45262d1d418eSSumit Saxena 			throttle_enabled_dev =
45272d1d418eSSumit Saxena 				target->io_throttle_enabled;
45282d1d418eSSumit Saxena 		}
45292d1d418eSSumit Saxena 
45302d1d418eSSumit Saxena 		if ((data_len_blks >= sc->io_throttle_data_length) &&
45312d1d418eSSumit Saxena 		     throttle_enabled_dev) {
45322d1d418eSSumit Saxena 			mpi3mr_atomic_sub(&sc->pend_large_data_sz, data_len_blks);
45332d1d418eSSumit Saxena 			ioc_pend_data_len = mpi3mr_atomic_read(
45342d1d418eSSumit Saxena 			    &sc->pend_large_data_sz);
45352d1d418eSSumit Saxena 			if (tg) {
45362d1d418eSSumit Saxena 				mpi3mr_atomic_sub(&tg->pend_large_data_sz,
45372d1d418eSSumit Saxena 					data_len_blks);
45382d1d418eSSumit Saxena 				tg_pend_data_len = mpi3mr_atomic_read(&tg->pend_large_data_sz);
45392d1d418eSSumit Saxena 				if (ratelimit % 1000) {
45402d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
45412d1d418eSSumit Saxena 						"large vd_io completion persist_id(%d), handle(0x%04x), data_len(%d),"
45422d1d418eSSumit Saxena 						"ioc_pending(%d), tg_pending(%d), ioc_low(%d), tg_low(%d)\n",
45432d1d418eSSumit Saxena 						    target->per_id,
45442d1d418eSSumit Saxena 						    target->dev_handle,
45452d1d418eSSumit Saxena 						    data_len_blks, ioc_pend_data_len,
45462d1d418eSSumit Saxena 						    tg_pend_data_len,
45472d1d418eSSumit Saxena 						    sc->io_throttle_low,
45482d1d418eSSumit Saxena 						    tg->low);
45492d1d418eSSumit Saxena 					ratelimit++;
45502d1d418eSSumit Saxena 				}
45512d1d418eSSumit Saxena 				if (tg->io_divert  && ((ioc_pend_data_len <=
45522d1d418eSSumit Saxena 				    sc->io_throttle_low) &&
45532d1d418eSSumit Saxena 				    (tg_pend_data_len <= tg->low))) {
45542d1d418eSSumit Saxena 					tg->io_divert = 0;
45552d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
45562d1d418eSSumit Saxena 						"VD: Coming out of divert perst_id(%d) tg_id(%d)\n",
45572d1d418eSSumit Saxena 						target->per_id, tg->id);
45582d1d418eSSumit Saxena 					mpi3mr_set_io_divert_for_all_vd_in_tg(
45592d1d418eSSumit Saxena 					    sc, tg, 0);
45602d1d418eSSumit Saxena 				}
45612d1d418eSSumit Saxena 			} else {
45622d1d418eSSumit Saxena 				if (ratelimit % 1000) {
45632d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
45642d1d418eSSumit Saxena 					    "large pd_io completion persist_id(%d), handle(0x%04x), data_len(%d), ioc_pending(%d), ioc_low(%d)\n",
45652d1d418eSSumit Saxena 					    target->per_id,
45662d1d418eSSumit Saxena 					    target->dev_handle,
45672d1d418eSSumit Saxena 					    data_len_blks, ioc_pend_data_len,
45682d1d418eSSumit Saxena 					    sc->io_throttle_low);
45692d1d418eSSumit Saxena 					ratelimit++;
45702d1d418eSSumit Saxena 				}
45712d1d418eSSumit Saxena 
45722d1d418eSSumit Saxena 				if (ioc_pend_data_len <= sc->io_throttle_low) {
45732d1d418eSSumit Saxena 					target->io_divert = 0;
45742d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
45752d1d418eSSumit Saxena 						"PD: Coming out of divert perst_id(%d)\n",
45762d1d418eSSumit Saxena 						target->per_id);
45772d1d418eSSumit Saxena 				}
45782d1d418eSSumit Saxena 			}
45792d1d418eSSumit Saxena 
45802d1d418eSSumit Saxena 			} else if (target->io_divert) {
45812d1d418eSSumit Saxena 			ioc_pend_data_len = mpi3mr_atomic_read(&sc->pend_large_data_sz);
45822d1d418eSSumit Saxena 			if (!tg) {
45832d1d418eSSumit Saxena 				if (ratelimit % 1000) {
45842d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
45852d1d418eSSumit Saxena 					    "pd_io completion persist_id(%d), handle(0x%04x), data_len(%d), ioc_pending(%d), ioc_low(%d)\n",
45862d1d418eSSumit Saxena 					    target->per_id,
45872d1d418eSSumit Saxena 					    target->dev_handle,
45882d1d418eSSumit Saxena 					    data_len_blks, ioc_pend_data_len,
45892d1d418eSSumit Saxena 					    sc->io_throttle_low);
45902d1d418eSSumit Saxena 					ratelimit++;
45912d1d418eSSumit Saxena 				}
45922d1d418eSSumit Saxena 
45932d1d418eSSumit Saxena 				if ( ioc_pend_data_len <= sc->io_throttle_low) {
45942d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
45952d1d418eSSumit Saxena 						"PD: Coming out of divert perst_id(%d)\n",
45962d1d418eSSumit Saxena 						target->per_id);
45972d1d418eSSumit Saxena 					target->io_divert = 0;
45982d1d418eSSumit Saxena 				}
45992d1d418eSSumit Saxena 
46002d1d418eSSumit Saxena 			} else if (ioc_pend_data_len <= sc->io_throttle_low) {
46012d1d418eSSumit Saxena 				tg_pend_data_len = mpi3mr_atomic_read(&tg->pend_large_data_sz);
46022d1d418eSSumit Saxena 				if (ratelimit % 1000) {
46032d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
46042d1d418eSSumit Saxena 						"vd_io completion persist_id(%d), handle(0x%04x), data_len(%d),"
46052d1d418eSSumit Saxena 						"ioc_pending(%d), tg_pending(%d), ioc_low(%d), tg_low(%d)\n",
46062d1d418eSSumit Saxena 						    target->per_id,
46072d1d418eSSumit Saxena 						    target->dev_handle,
46082d1d418eSSumit Saxena 						    data_len_blks, ioc_pend_data_len,
46092d1d418eSSumit Saxena 						    tg_pend_data_len,
46102d1d418eSSumit Saxena 						    sc->io_throttle_low,
46112d1d418eSSumit Saxena 						    tg->low);
46122d1d418eSSumit Saxena 					ratelimit++;
46132d1d418eSSumit Saxena 				}
46142d1d418eSSumit Saxena 				if (tg->io_divert  && (tg_pend_data_len <= tg->low)) {
46152d1d418eSSumit Saxena 					tg->io_divert = 0;
46162d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
46172d1d418eSSumit Saxena 						"VD: Coming out of divert perst_id(%d) tg_id(%d)\n",
46182d1d418eSSumit Saxena 						target->per_id, tg->id);
46192d1d418eSSumit Saxena 					mpi3mr_set_io_divert_for_all_vd_in_tg(
46202d1d418eSSumit Saxena 					    sc, tg, 0);
46212d1d418eSSumit Saxena 				}
46222d1d418eSSumit Saxena 
46232d1d418eSSumit Saxena 			}
46242d1d418eSSumit Saxena 		}
46252d1d418eSSumit Saxena 	}
46262d1d418eSSumit Saxena 
46272d1d418eSSumit Saxena 	if (success_desc) {
46282d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
46292d1d418eSSumit Saxena 		goto out_success;
46302d1d418eSSumit Saxena 	}
46312d1d418eSSumit Saxena 
46322d1d418eSSumit Saxena 	if (ioc_status == MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN
46332d1d418eSSumit Saxena 	    && xfer_count == 0 && (scsi_status == MPI3_SCSI_STATUS_BUSY ||
46342d1d418eSSumit Saxena 	    scsi_status == MPI3_SCSI_STATUS_RESERVATION_CONFLICT ||
46352d1d418eSSumit Saxena 	    scsi_status == MPI3_SCSI_STATUS_TASK_SET_FULL))
46362d1d418eSSumit Saxena 		ioc_status = MPI3_IOCSTATUS_SUCCESS;
46372d1d418eSSumit Saxena 
46382d1d418eSSumit Saxena 	if ((sense_state == MPI3_SCSI_STATE_SENSE_VALID) && sense_count
46392d1d418eSSumit Saxena 	    && sense_buf) {
46402d1d418eSSumit Saxena 		int sense_len, returned_sense_len;
46412d1d418eSSumit Saxena 
46422d1d418eSSumit Saxena 		returned_sense_len = min(le32toh(sense_count),
46432d1d418eSSumit Saxena 		    sizeof(struct scsi_sense_data));
46442d1d418eSSumit Saxena 		if (returned_sense_len < csio->sense_len)
46452d1d418eSSumit Saxena 			csio->sense_resid = csio->sense_len -
46462d1d418eSSumit Saxena 			    returned_sense_len;
46472d1d418eSSumit Saxena 		else
46482d1d418eSSumit Saxena 			csio->sense_resid = 0;
46492d1d418eSSumit Saxena 
46502d1d418eSSumit Saxena 		sense_len = min(returned_sense_len,
46512d1d418eSSumit Saxena 		    csio->sense_len - csio->sense_resid);
46522d1d418eSSumit Saxena 		bzero(&csio->sense_data, sizeof(csio->sense_data));
46532d1d418eSSumit Saxena 		bcopy(sense_buf, &csio->sense_data, sense_len);
46542d1d418eSSumit Saxena 		ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
46552d1d418eSSumit Saxena 	}
46562d1d418eSSumit Saxena 
46572d1d418eSSumit Saxena 	switch (ioc_status) {
46582d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_BUSY:
46592d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INSUFFICIENT_RESOURCES:
46602d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQUEUE_REQ);
46612d1d418eSSumit Saxena 		break;
46622d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
46632d1d418eSSumit Saxena 		/*
46642d1d418eSSumit Saxena 		 * If devinfo is 0 this will be a volume.  In that case don't
46652d1d418eSSumit Saxena 		 * tell CAM that the volume is not there.  We want volumes to
46662d1d418eSSumit Saxena 		 * be enumerated until they are deleted/removed, not just
46672d1d418eSSumit Saxena 		 * failed.
46682d1d418eSSumit Saxena 		 */
46692d1d418eSSumit Saxena 		if (cm->targ->devinfo == 0)
46702d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
46712d1d418eSSumit Saxena 		else
46722d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
46732d1d418eSSumit Saxena 		break;
46742d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_TASK_TERMINATED:
46752d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED:
46762d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_EXT_TERMINATED:
46772d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_SCSI_BUSY);
46782d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_TRACE,
46792d1d418eSSumit Saxena 		    "func: %s line:%d tgt %u Hosttag %u loginfo %x\n",
46802d1d418eSSumit Saxena 		    __func__, __LINE__,
46812d1d418eSSumit Saxena 		    target_id, cm->hosttag,
46822d1d418eSSumit Saxena 		    le32toh(scsi_reply->IOCLogInfo));
46832d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_TRACE,
46842d1d418eSSumit Saxena 		    "SCSIStatus %x SCSIState %x xfercount %u\n",
46852d1d418eSSumit Saxena 		    scsi_reply->SCSIStatus, scsi_reply->SCSIState,
46862d1d418eSSumit Saxena 		    le32toh(xfer_count));
46872d1d418eSSumit Saxena 		break;
46882d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_DATA_OVERRUN:
46892d1d418eSSumit Saxena 		/* resid is ignored for this condition */
46902d1d418eSSumit Saxena 		csio->resid = 0;
46912d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_DATA_RUN_ERR);
46922d1d418eSSumit Saxena 		break;
46932d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN:
46942d1d418eSSumit Saxena 		csio->resid = cm->length - le32toh(xfer_count);
46952d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR:
46962d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SUCCESS:
46972d1d418eSSumit Saxena 		if ((scsi_reply->IOCStatus & MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK) ==
46982d1d418eSSumit Saxena 		    MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR)
46992d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_XINFO, "func: %s line: %d recovered error\n",  __func__, __LINE__);
47002d1d418eSSumit Saxena 
47012d1d418eSSumit Saxena 		/* Completion failed at the transport level. */
47022d1d418eSSumit Saxena 		if (scsi_reply->SCSIState & (MPI3_SCSI_STATE_NO_SCSI_STATUS |
47032d1d418eSSumit Saxena 		    MPI3_SCSI_STATE_TERMINATED)) {
47042d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
47052d1d418eSSumit Saxena 			break;
47062d1d418eSSumit Saxena 		}
47072d1d418eSSumit Saxena 
47082d1d418eSSumit Saxena 		/* In a modern packetized environment, an autosense failure
47092d1d418eSSumit Saxena 		 * implies that there's not much else that can be done to
47102d1d418eSSumit Saxena 		 * recover the command.
47112d1d418eSSumit Saxena 		 */
47122d1d418eSSumit Saxena 		if (scsi_reply->SCSIState & MPI3_SCSI_STATE_SENSE_VALID) {
47132d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_AUTOSENSE_FAIL);
47142d1d418eSSumit Saxena 			break;
47152d1d418eSSumit Saxena 		}
47162d1d418eSSumit Saxena 
47172d1d418eSSumit Saxena 		/*
47182d1d418eSSumit Saxena 		 * Intentionally override the normal SCSI status reporting
47192d1d418eSSumit Saxena 		 * for these two cases.  These are likely to happen in a
47202d1d418eSSumit Saxena 		 * multi-initiator environment, and we want to make sure that
47212d1d418eSSumit Saxena 		 * CAM retries these commands rather than fail them.
47222d1d418eSSumit Saxena 		 */
47232d1d418eSSumit Saxena 		if ((scsi_reply->SCSIStatus == MPI3_SCSI_STATUS_COMMAND_TERMINATED) ||
47242d1d418eSSumit Saxena 		    (scsi_reply->SCSIStatus == MPI3_SCSI_STATUS_TASK_ABORTED)) {
47252d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_REQ_ABORTED);
47262d1d418eSSumit Saxena 			break;
47272d1d418eSSumit Saxena 		}
47282d1d418eSSumit Saxena 
47292d1d418eSSumit Saxena 		/* Handle normal status and sense */
47302d1d418eSSumit Saxena 		csio->scsi_status = scsi_reply->SCSIStatus;
47312d1d418eSSumit Saxena 		if (scsi_reply->SCSIStatus == MPI3_SCSI_STATUS_GOOD)
47322d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
47332d1d418eSSumit Saxena 		else
47342d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_SCSI_STATUS_ERROR);
47352d1d418eSSumit Saxena 
47362d1d418eSSumit Saxena 		if (scsi_reply->SCSIState & MPI3_SCSI_STATE_SENSE_VALID) {
47372d1d418eSSumit Saxena 			int sense_len, returned_sense_len;
47382d1d418eSSumit Saxena 
47392d1d418eSSumit Saxena 			returned_sense_len = min(le32toh(scsi_reply->SenseCount),
47402d1d418eSSumit Saxena 			    sizeof(struct scsi_sense_data));
47412d1d418eSSumit Saxena 			if (returned_sense_len < csio->sense_len)
47422d1d418eSSumit Saxena 				csio->sense_resid = csio->sense_len -
47432d1d418eSSumit Saxena 				    returned_sense_len;
47442d1d418eSSumit Saxena 			else
47452d1d418eSSumit Saxena 				csio->sense_resid = 0;
47462d1d418eSSumit Saxena 
47472d1d418eSSumit Saxena 			sense_len = min(returned_sense_len,
47482d1d418eSSumit Saxena 			    csio->sense_len - csio->sense_resid);
47492d1d418eSSumit Saxena 			bzero(&csio->sense_data, sizeof(csio->sense_data));
47502d1d418eSSumit Saxena 			bcopy(cm->sense, &csio->sense_data, sense_len);
47512d1d418eSSumit Saxena 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
47522d1d418eSSumit Saxena 		}
47532d1d418eSSumit Saxena 
47542d1d418eSSumit Saxena 		break;
47552d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INVALID_SGL:
47562d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_UNREC_HBA_ERROR);
47572d1d418eSSumit Saxena 		break;
47582d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_EEDP_GUARD_ERROR:
47592d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR:
47602d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR:
47612d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_PROTOCOL_ERROR:
47622d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INVALID_FUNCTION:
47632d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INTERNAL_ERROR:
47642d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INVALID_FIELD:
47652d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INVALID_STATE:
47662d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_IO_DATA_ERROR:
47672d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
47682d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_INSUFFICIENT_POWER:
47692d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
47702d1d418eSSumit Saxena 	default:
47712d1d418eSSumit Saxena 		csio->resid = cm->length;
47722d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
47732d1d418eSSumit Saxena 		break;
47742d1d418eSSumit Saxena 	}
47752d1d418eSSumit Saxena 
47762d1d418eSSumit Saxena out_success:
47772d1d418eSSumit Saxena 	if (mpi3mr_get_ccbstatus(ccb) != CAM_REQ_CMP) {
47782d1d418eSSumit Saxena 		ccb->ccb_h.status |= CAM_DEV_QFRZN;
47792d1d418eSSumit Saxena 		xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
47802d1d418eSSumit Saxena 	}
47812d1d418eSSumit Saxena 
47822d1d418eSSumit Saxena 	mpi3mr_atomic_dec(&cm->targ->outstanding);
47832d1d418eSSumit Saxena 	mpi3mr_cmd_done(sc, cm);
47842d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_TRACE, "Completion IO path :"
47852d1d418eSSumit Saxena 		" cdb[0]: %x targetid: 0x%x SMID: %x ioc_status: 0x%x ioc_loginfo: 0x%x scsi_status: 0x%x "
47862d1d418eSSumit Saxena 		"scsi_state: 0x%x response_data: 0x%x\n", scsi_cdb[0], target_id, host_tag,
47872d1d418eSSumit Saxena 		ioc_status, ioc_loginfo, scsi_status, scsi_state, resp_data);
47882d1d418eSSumit Saxena 	mpi3mr_atomic_dec(&sc->fw_outstanding);
47892d1d418eSSumit Saxena out:
47902d1d418eSSumit Saxena 
47912d1d418eSSumit Saxena 	if (sense_buf)
47922d1d418eSSumit Saxena 		mpi3mr_repost_sense_buf(sc,
47932d1d418eSSumit Saxena 		    scsi_reply->SenseDataBufferAddress);
47942d1d418eSSumit Saxena 	return;
47952d1d418eSSumit Saxena }
47962d1d418eSSumit Saxena 
47972d1d418eSSumit Saxena /*
47982d1d418eSSumit Saxena  * mpi3mr_complete_io_cmd:	ISR routine for IO commands
47992d1d418eSSumit Saxena  * @sc:				Adapter's soft instance
48002d1d418eSSumit Saxena  * @irq_ctx:			Driver's internal per IRQ structure
48012d1d418eSSumit Saxena  *
48022d1d418eSSumit Saxena  * This function processes IO command completions.
48032d1d418eSSumit Saxena  */
48042d1d418eSSumit Saxena int mpi3mr_complete_io_cmd(struct mpi3mr_softc *sc,
48052d1d418eSSumit Saxena     struct mpi3mr_irq_context *irq_ctx)
48062d1d418eSSumit Saxena {
48072d1d418eSSumit Saxena 	struct mpi3mr_op_reply_queue *op_reply_q = irq_ctx->op_reply_q;
48082d1d418eSSumit Saxena 	U32 exp_phase = op_reply_q->ephase;
48092d1d418eSSumit Saxena 	U32 reply_ci = op_reply_q->ci;
48102d1d418eSSumit Saxena 	U32 num_op_replies = 0;
48112d1d418eSSumit Saxena 	U64 reply_dma = 0;
48122d1d418eSSumit Saxena 	Mpi3DefaultReplyDescriptor_t *reply_desc;
48132d1d418eSSumit Saxena 	U16 req_qid = 0;
48142d1d418eSSumit Saxena 
48152d1d418eSSumit Saxena 	mtx_lock_spin(&op_reply_q->q_lock);
48162d1d418eSSumit Saxena 	if (op_reply_q->in_use == false) {
48172d1d418eSSumit Saxena 		op_reply_q->in_use = true;
48182d1d418eSSumit Saxena 		mtx_unlock_spin(&op_reply_q->q_lock);
48192d1d418eSSumit Saxena 	} else {
48202d1d418eSSumit Saxena 		mtx_unlock_spin(&op_reply_q->q_lock);
48212d1d418eSSumit Saxena 		return 0;
48222d1d418eSSumit Saxena 	}
48232d1d418eSSumit Saxena 
48242d1d418eSSumit Saxena 	reply_desc = (Mpi3DefaultReplyDescriptor_t *)op_reply_q->q_base + reply_ci;
48252d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_TRACE, "[QID:%d]:reply_desc: (%pa) reply_ci: %x"
48262d1d418eSSumit Saxena 		" reply_desc->ReplyFlags: 0x%x\n"
48272d1d418eSSumit Saxena 		"reply_q_base_phys: %#016jx reply_q_base: (%pa) exp_phase: %x\n",
48282d1d418eSSumit Saxena 		op_reply_q->qid, reply_desc, reply_ci, reply_desc->ReplyFlags, op_reply_q->q_base_phys,
48292d1d418eSSumit Saxena 		op_reply_q->q_base, exp_phase);
48302d1d418eSSumit Saxena 
48312d1d418eSSumit Saxena 	if (((reply_desc->ReplyFlags &
48322d1d418eSSumit Saxena 	     MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) || !op_reply_q->qid) {
48332d1d418eSSumit Saxena 		mtx_lock_spin(&op_reply_q->q_lock);
48342d1d418eSSumit Saxena 		op_reply_q->in_use = false;
48352d1d418eSSumit Saxena 		mtx_unlock_spin(&op_reply_q->q_lock);
48362d1d418eSSumit Saxena 		return 0;
48372d1d418eSSumit Saxena 	}
48382d1d418eSSumit Saxena 
48392d1d418eSSumit Saxena 	do {
48402d1d418eSSumit Saxena 		req_qid = reply_desc->RequestQueueID;
48412d1d418eSSumit Saxena 		sc->op_req_q[req_qid - 1].ci =
48422d1d418eSSumit Saxena 		    reply_desc->RequestQueueCI;
48432d1d418eSSumit Saxena 
48442d1d418eSSumit Saxena 		mpi3mr_process_op_reply_desc(sc, reply_desc, &reply_dma);
48452d1d418eSSumit Saxena 		mpi3mr_atomic_dec(&op_reply_q->pend_ios);
48462d1d418eSSumit Saxena 		if (reply_dma)
48472d1d418eSSumit Saxena 			mpi3mr_repost_reply_buf(sc, reply_dma);
48482d1d418eSSumit Saxena 		num_op_replies++;
48492d1d418eSSumit Saxena 		if (++reply_ci == op_reply_q->num_replies) {
48502d1d418eSSumit Saxena 			reply_ci = 0;
48512d1d418eSSumit Saxena 			exp_phase ^= 1;
48522d1d418eSSumit Saxena 		}
48532d1d418eSSumit Saxena 		reply_desc =
48542d1d418eSSumit Saxena 		    (Mpi3DefaultReplyDescriptor_t *)op_reply_q->q_base + reply_ci;
48552d1d418eSSumit Saxena 		if ((reply_desc->ReplyFlags &
48562d1d418eSSumit Saxena 		     MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
48572d1d418eSSumit Saxena 			break;
48582d1d418eSSumit Saxena 	} while (1);
48592d1d418eSSumit Saxena 
48602d1d418eSSumit Saxena 
48612d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_OPER_REPLY_Q_N_CI_OFFSET(op_reply_q->qid), reply_ci);
48622d1d418eSSumit Saxena 	op_reply_q->ci = reply_ci;
48632d1d418eSSumit Saxena 	op_reply_q->ephase = exp_phase;
48642d1d418eSSumit Saxena 	mtx_lock_spin(&op_reply_q->q_lock);
48652d1d418eSSumit Saxena 	op_reply_q->in_use = false;
48662d1d418eSSumit Saxena 	mtx_unlock_spin(&op_reply_q->q_lock);
48672d1d418eSSumit Saxena 	return num_op_replies;
48682d1d418eSSumit Saxena }
48692d1d418eSSumit Saxena 
48702d1d418eSSumit Saxena /*
48712d1d418eSSumit Saxena  * mpi3mr_isr:			Primary ISR function
48722d1d418eSSumit Saxena  * privdata:			Driver's internal per IRQ structure
48732d1d418eSSumit Saxena  *
48742d1d418eSSumit Saxena  * This is driver's primary ISR function which is being called whenever any admin/IO
48752d1d418eSSumit Saxena  * command completion.
48762d1d418eSSumit Saxena  */
48772d1d418eSSumit Saxena void mpi3mr_isr(void *privdata)
48782d1d418eSSumit Saxena {
48792d1d418eSSumit Saxena 	struct mpi3mr_irq_context *irq_ctx = (struct mpi3mr_irq_context *)privdata;
48802d1d418eSSumit Saxena 	struct mpi3mr_softc *sc = irq_ctx->sc;
48812d1d418eSSumit Saxena 	U16 msi_idx;
48822d1d418eSSumit Saxena 
48832d1d418eSSumit Saxena 	if (!irq_ctx)
48842d1d418eSSumit Saxena 		return;
48852d1d418eSSumit Saxena 
48862d1d418eSSumit Saxena 	msi_idx = irq_ctx->msix_index;
48872d1d418eSSumit Saxena 
48882d1d418eSSumit Saxena 	if (!sc->intr_enabled)
48892d1d418eSSumit Saxena 		return;
48902d1d418eSSumit Saxena 
48912d1d418eSSumit Saxena 	if (!msi_idx)
48922d1d418eSSumit Saxena 		mpi3mr_complete_admin_cmd(sc);
48932d1d418eSSumit Saxena 
48942d1d418eSSumit Saxena 	if (irq_ctx->op_reply_q && irq_ctx->op_reply_q->qid) {
48952d1d418eSSumit Saxena 		mpi3mr_complete_io_cmd(sc, irq_ctx);
48962d1d418eSSumit Saxena 	}
48972d1d418eSSumit Saxena }
48982d1d418eSSumit Saxena 
48992d1d418eSSumit Saxena /*
49002d1d418eSSumit Saxena  * mpi3mr_alloc_requests - Allocates host commands
49012d1d418eSSumit Saxena  * @sc: Adapter reference
49022d1d418eSSumit Saxena  *
49032d1d418eSSumit Saxena  * This function allocates controller supported host commands
49042d1d418eSSumit Saxena  *
49052d1d418eSSumit Saxena  * Return: 0 on success and proper error codes on failure
49062d1d418eSSumit Saxena  */
49072d1d418eSSumit Saxena int
49082d1d418eSSumit Saxena mpi3mr_alloc_requests(struct mpi3mr_softc *sc)
49092d1d418eSSumit Saxena {
49102d1d418eSSumit Saxena 	struct mpi3mr_cmd *cmd;
49112d1d418eSSumit Saxena 	int i, j, nsegs, ret;
49122d1d418eSSumit Saxena 
49132d1d418eSSumit Saxena 	nsegs = MPI3MR_SG_DEPTH;
49142d1d418eSSumit Saxena 	ret = bus_dma_tag_create( sc->mpi3mr_parent_dmat,    /* parent */
49152d1d418eSSumit Saxena 				1, 0,			/* algnmnt, boundary */
49162d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* lowaddr */
49172d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
49182d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
49192d1d418eSSumit Saxena 				MAXPHYS,/* maxsize */
49202d1d418eSSumit Saxena                                 nsegs,			/* nsegments */
49212d1d418eSSumit Saxena 				MAXPHYS,/* maxsegsize */
49222d1d418eSSumit Saxena                                 BUS_DMA_ALLOCNOW,	/* flags */
49232d1d418eSSumit Saxena                                 busdma_lock_mutex,	/* lockfunc */
49242d1d418eSSumit Saxena 				&sc->io_lock,	/* lockarg */
49252d1d418eSSumit Saxena 				&sc->buffer_dmat);
49262d1d418eSSumit Saxena 	if (ret) {
49272d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate buffer DMA tag ret: %d\n", ret);
49282d1d418eSSumit Saxena 		return (ENOMEM);
49292d1d418eSSumit Saxena         }
49302d1d418eSSumit Saxena 
49312d1d418eSSumit Saxena 	/*
49322d1d418eSSumit Saxena 	 * sc->cmd_list is an array of struct mpi3mr_cmd pointers.
49332d1d418eSSumit Saxena 	 * Allocate the dynamic array first and then allocate individual
49342d1d418eSSumit Saxena 	 * commands.
49352d1d418eSSumit Saxena 	 */
49362d1d418eSSumit Saxena 	sc->cmd_list = malloc(sizeof(struct mpi3mr_cmd *) * sc->max_host_ios,
49372d1d418eSSumit Saxena 	    M_MPI3MR, M_NOWAIT | M_ZERO);
49382d1d418eSSumit Saxena 
49392d1d418eSSumit Saxena 	if (!sc->cmd_list) {
49402d1d418eSSumit Saxena 		device_printf(sc->mpi3mr_dev, "Cannot alloc memory for mpt_cmd_list.\n");
49412d1d418eSSumit Saxena 		return (ENOMEM);
49422d1d418eSSumit Saxena 	}
49432d1d418eSSumit Saxena 
49442d1d418eSSumit Saxena 	for (i = 0; i < sc->max_host_ios; i++) {
49452d1d418eSSumit Saxena 		sc->cmd_list[i] = malloc(sizeof(struct mpi3mr_cmd),
49462d1d418eSSumit Saxena 		    M_MPI3MR, M_NOWAIT | M_ZERO);
49472d1d418eSSumit Saxena 		if (!sc->cmd_list[i]) {
49482d1d418eSSumit Saxena 			for (j = 0; j < i; j++)
49492d1d418eSSumit Saxena 				free(sc->cmd_list[j], M_MPI3MR);
49502d1d418eSSumit Saxena 			free(sc->cmd_list, M_MPI3MR);
49512d1d418eSSumit Saxena 			sc->cmd_list = NULL;
49522d1d418eSSumit Saxena 			return (ENOMEM);
49532d1d418eSSumit Saxena 		}
49542d1d418eSSumit Saxena 	}
49552d1d418eSSumit Saxena 
49562d1d418eSSumit Saxena 	for (i = 1; i < sc->max_host_ios; i++) {
49572d1d418eSSumit Saxena 		cmd = sc->cmd_list[i];
49582d1d418eSSumit Saxena 		cmd->hosttag = i;
49592d1d418eSSumit Saxena 		cmd->sc = sc;
49602d1d418eSSumit Saxena 		cmd->state = MPI3MR_CMD_STATE_BUSY;
49612d1d418eSSumit Saxena 		callout_init_mtx(&cmd->callout, &sc->mpi3mr_mtx, 0);
49622d1d418eSSumit Saxena 		cmd->ccb = NULL;
49632d1d418eSSumit Saxena 		TAILQ_INSERT_TAIL(&(sc->cmd_list_head), cmd, next);
49642d1d418eSSumit Saxena 		if (bus_dmamap_create(sc->buffer_dmat, 0, &cmd->dmamap))
49652d1d418eSSumit Saxena 			return ENOMEM;
49662d1d418eSSumit Saxena 	}
49672d1d418eSSumit Saxena 	return (0);
49682d1d418eSSumit Saxena }
49692d1d418eSSumit Saxena 
49702d1d418eSSumit Saxena /*
49712d1d418eSSumit Saxena  * mpi3mr_get_command:		Get a coomand structure from free command pool
49722d1d418eSSumit Saxena  * @sc:				Adapter soft instance
49732d1d418eSSumit Saxena  * Return:			MPT command reference
49742d1d418eSSumit Saxena  *
49752d1d418eSSumit Saxena  * This function returns an MPT command to the caller.
49762d1d418eSSumit Saxena  */
49772d1d418eSSumit Saxena struct mpi3mr_cmd *
49782d1d418eSSumit Saxena mpi3mr_get_command(struct mpi3mr_softc *sc)
49792d1d418eSSumit Saxena {
49802d1d418eSSumit Saxena 	struct mpi3mr_cmd *cmd = NULL;
49812d1d418eSSumit Saxena 
49822d1d418eSSumit Saxena 	mtx_lock(&sc->cmd_pool_lock);
49832d1d418eSSumit Saxena 	if (!TAILQ_EMPTY(&sc->cmd_list_head)) {
49842d1d418eSSumit Saxena 		cmd = TAILQ_FIRST(&sc->cmd_list_head);
49852d1d418eSSumit Saxena 		TAILQ_REMOVE(&sc->cmd_list_head, cmd, next);
49862d1d418eSSumit Saxena 	} else {
49872d1d418eSSumit Saxena 		goto out;
49882d1d418eSSumit Saxena 	}
49892d1d418eSSumit Saxena 
49902d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_TRACE, "Get command SMID: 0x%x\n", cmd->hosttag);
49912d1d418eSSumit Saxena 
49922d1d418eSSumit Saxena 	memset((uint8_t *)&cmd->io_request, 0, MPI3MR_AREQ_FRAME_SZ);
49932d1d418eSSumit Saxena 	cmd->data_dir = 0;
49942d1d418eSSumit Saxena 	cmd->ccb = NULL;
49952d1d418eSSumit Saxena 	cmd->targ = NULL;
49962d1d418eSSumit Saxena 	cmd->state = MPI3MR_CMD_STATE_BUSY;
49972d1d418eSSumit Saxena 	cmd->data = NULL;
49982d1d418eSSumit Saxena 	cmd->length = 0;
49992d1d418eSSumit Saxena out:
50002d1d418eSSumit Saxena 	mtx_unlock(&sc->cmd_pool_lock);
50012d1d418eSSumit Saxena 	return cmd;
50022d1d418eSSumit Saxena }
50032d1d418eSSumit Saxena 
50042d1d418eSSumit Saxena /*
50052d1d418eSSumit Saxena  * mpi3mr_release_command:	Return a cmd to free command pool
50062d1d418eSSumit Saxena  * input:			Command packet for return to free command pool
50072d1d418eSSumit Saxena  *
50082d1d418eSSumit Saxena  * This function returns an MPT command to the free command list.
50092d1d418eSSumit Saxena  */
50102d1d418eSSumit Saxena void
50112d1d418eSSumit Saxena mpi3mr_release_command(struct mpi3mr_cmd *cmd)
50122d1d418eSSumit Saxena {
50132d1d418eSSumit Saxena 	struct mpi3mr_softc *sc = cmd->sc;
50142d1d418eSSumit Saxena 
50152d1d418eSSumit Saxena 	mtx_lock(&sc->cmd_pool_lock);
50162d1d418eSSumit Saxena 	TAILQ_INSERT_HEAD(&(sc->cmd_list_head), cmd, next);
50172d1d418eSSumit Saxena 	cmd->state = MPI3MR_CMD_STATE_FREE;
50182d1d418eSSumit Saxena 	cmd->req_qidx = 0;
50192d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_TRACE, "Release command SMID: 0x%x\n", cmd->hosttag);
50202d1d418eSSumit Saxena 	mtx_unlock(&sc->cmd_pool_lock);
50212d1d418eSSumit Saxena 
50222d1d418eSSumit Saxena 	return;
50232d1d418eSSumit Saxena }
50242d1d418eSSumit Saxena 
50252d1d418eSSumit Saxena  /**
50262d1d418eSSumit Saxena  * mpi3mr_free_ioctl_dma_memory - free memory for ioctl dma
50272d1d418eSSumit Saxena  * @sc: Adapter instance reference
50282d1d418eSSumit Saxena  *
50292d1d418eSSumit Saxena  * Free the DMA memory allocated for IOCTL handling purpose.
50302d1d418eSSumit Saxena  *
50312d1d418eSSumit Saxena  * Return: None
50322d1d418eSSumit Saxena  */
50332d1d418eSSumit Saxena static void mpi3mr_free_ioctl_dma_memory(struct mpi3mr_softc *sc)
50342d1d418eSSumit Saxena {
50352d1d418eSSumit Saxena 	U16 i;
50362d1d418eSSumit Saxena 	struct dma_memory_desc *mem_desc;
50372d1d418eSSumit Saxena 
50382d1d418eSSumit Saxena 	for (i=0; i<MPI3MR_NUM_IOCTL_SGE; i++) {
50392d1d418eSSumit Saxena 		mem_desc = &sc->ioctl_sge[i];
50402d1d418eSSumit Saxena 		if (mem_desc->addr && mem_desc->dma_addr) {
50412d1d418eSSumit Saxena 			bus_dmamap_unload(mem_desc->tag, mem_desc->dmamap);
50422d1d418eSSumit Saxena 			bus_dmamem_free(mem_desc->tag, mem_desc->addr, mem_desc->dmamap);
50432d1d418eSSumit Saxena 			mem_desc->addr = NULL;
50442d1d418eSSumit Saxena 			if (mem_desc->tag != NULL)
50452d1d418eSSumit Saxena 				bus_dma_tag_destroy(mem_desc->tag);
50462d1d418eSSumit Saxena 		}
50472d1d418eSSumit Saxena 	}
50482d1d418eSSumit Saxena 
50492d1d418eSSumit Saxena 	mem_desc = &sc->ioctl_chain_sge;
50502d1d418eSSumit Saxena 	if (mem_desc->addr && mem_desc->dma_addr) {
50512d1d418eSSumit Saxena 		bus_dmamap_unload(mem_desc->tag, mem_desc->dmamap);
50522d1d418eSSumit Saxena 		bus_dmamem_free(mem_desc->tag, mem_desc->addr, mem_desc->dmamap);
50532d1d418eSSumit Saxena 		mem_desc->addr = NULL;
50542d1d418eSSumit Saxena 		if (mem_desc->tag != NULL)
50552d1d418eSSumit Saxena 			bus_dma_tag_destroy(mem_desc->tag);
50562d1d418eSSumit Saxena 	}
50572d1d418eSSumit Saxena 
50582d1d418eSSumit Saxena 	mem_desc = &sc->ioctl_resp_sge;
50592d1d418eSSumit Saxena 	if (mem_desc->addr && mem_desc->dma_addr) {
50602d1d418eSSumit Saxena 		bus_dmamap_unload(mem_desc->tag, mem_desc->dmamap);
50612d1d418eSSumit Saxena 		bus_dmamem_free(mem_desc->tag, mem_desc->addr, mem_desc->dmamap);
50622d1d418eSSumit Saxena 		mem_desc->addr = NULL;
50632d1d418eSSumit Saxena 		if (mem_desc->tag != NULL)
50642d1d418eSSumit Saxena 			bus_dma_tag_destroy(mem_desc->tag);
50652d1d418eSSumit Saxena 	}
50662d1d418eSSumit Saxena 
50672d1d418eSSumit Saxena 	sc->ioctl_sges_allocated = false;
50682d1d418eSSumit Saxena }
50692d1d418eSSumit Saxena 
50702d1d418eSSumit Saxena /**
50712d1d418eSSumit Saxena  * mpi3mr_alloc_ioctl_dma_memory - Alloc memory for ioctl dma
50722d1d418eSSumit Saxena  * @sc: Adapter instance reference
50732d1d418eSSumit Saxena  *
50742d1d418eSSumit Saxena  * This function allocates dmaable memory required to handle the
50752d1d418eSSumit Saxena  * application issued MPI3 IOCTL requests.
50762d1d418eSSumit Saxena  *
50772d1d418eSSumit Saxena  * Return: None
50782d1d418eSSumit Saxena  */
50792d1d418eSSumit Saxena void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_softc *sc)
50802d1d418eSSumit Saxena {
50812d1d418eSSumit Saxena 	struct dma_memory_desc *mem_desc;
50822d1d418eSSumit Saxena 	U16 i;
50832d1d418eSSumit Saxena 
50842d1d418eSSumit Saxena 	for (i=0; i<MPI3MR_NUM_IOCTL_SGE; i++) {
50852d1d418eSSumit Saxena 		mem_desc = &sc->ioctl_sge[i];
50862d1d418eSSumit Saxena 		mem_desc->size = MPI3MR_IOCTL_SGE_SIZE;
50872d1d418eSSumit Saxena 
50882d1d418eSSumit Saxena 		if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
50892d1d418eSSumit Saxena 					4, 0,			/* algnmnt, boundary */
50902d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
50912d1d418eSSumit Saxena 					BUS_SPACE_MAXADDR,	/* highaddr */
50922d1d418eSSumit Saxena 					NULL, NULL,		/* filter, filterarg */
50932d1d418eSSumit Saxena 					mem_desc->size,		/* maxsize */
50942d1d418eSSumit Saxena 					1,			/* nsegments */
50952d1d418eSSumit Saxena 					mem_desc->size,		/* maxsegsize */
50962d1d418eSSumit Saxena 					0,			/* flags */
50972d1d418eSSumit Saxena 					NULL, NULL,		/* lockfunc, lockarg */
50982d1d418eSSumit Saxena 					&mem_desc->tag)) {
50992d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
51002d1d418eSSumit Saxena 			goto out_failed;
51012d1d418eSSumit Saxena 		}
51022d1d418eSSumit Saxena 
51032d1d418eSSumit Saxena 		if (bus_dmamem_alloc(mem_desc->tag, (void **)&mem_desc->addr,
51042d1d418eSSumit Saxena 		    BUS_DMA_NOWAIT, &mem_desc->dmamap)) {
51052d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
51062d1d418eSSumit Saxena 			goto out_failed;
51072d1d418eSSumit Saxena 		}
51082d1d418eSSumit Saxena 		bzero(mem_desc->addr, mem_desc->size);
51092d1d418eSSumit Saxena 		bus_dmamap_load(mem_desc->tag, mem_desc->dmamap, mem_desc->addr, mem_desc->size,
51102d1d418eSSumit Saxena 		    mpi3mr_memaddr_cb, &mem_desc->dma_addr, 0);
51112d1d418eSSumit Saxena 
51122d1d418eSSumit Saxena 		if (!mem_desc->addr)
51132d1d418eSSumit Saxena 			goto out_failed;
51142d1d418eSSumit Saxena 	}
51152d1d418eSSumit Saxena 
51162d1d418eSSumit Saxena 	mem_desc = &sc->ioctl_chain_sge;
51172d1d418eSSumit Saxena 	mem_desc->size = MPI3MR_4K_PGSZ;
51182d1d418eSSumit Saxena 	if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
51192d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
51202d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
51212d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
51222d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
51232d1d418eSSumit Saxena 				mem_desc->size,		/* maxsize */
51242d1d418eSSumit Saxena 				1,			/* nsegments */
51252d1d418eSSumit Saxena 				mem_desc->size,		/* maxsegsize */
51262d1d418eSSumit Saxena 				0,			/* flags */
51272d1d418eSSumit Saxena 				NULL, NULL,		/* lockfunc, lockarg */
51282d1d418eSSumit Saxena 				&mem_desc->tag)) {
51292d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
51302d1d418eSSumit Saxena 		goto out_failed;
51312d1d418eSSumit Saxena 	}
51322d1d418eSSumit Saxena 
51332d1d418eSSumit Saxena 	if (bus_dmamem_alloc(mem_desc->tag, (void **)&mem_desc->addr,
51342d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &mem_desc->dmamap)) {
51352d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
51362d1d418eSSumit Saxena 		goto out_failed;
51372d1d418eSSumit Saxena 	}
51382d1d418eSSumit Saxena 	bzero(mem_desc->addr, mem_desc->size);
51392d1d418eSSumit Saxena 	bus_dmamap_load(mem_desc->tag, mem_desc->dmamap, mem_desc->addr, mem_desc->size,
51402d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &mem_desc->dma_addr, 0);
51412d1d418eSSumit Saxena 
51422d1d418eSSumit Saxena 	if (!mem_desc->addr)
51432d1d418eSSumit Saxena 		goto out_failed;
51442d1d418eSSumit Saxena 
51452d1d418eSSumit Saxena 	mem_desc = &sc->ioctl_resp_sge;
51462d1d418eSSumit Saxena 	mem_desc->size = MPI3MR_4K_PGSZ;
51472d1d418eSSumit Saxena 	if (bus_dma_tag_create(sc->mpi3mr_parent_dmat,    /* parent */
51482d1d418eSSumit Saxena 				4, 0,			/* algnmnt, boundary */
51492d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
51502d1d418eSSumit Saxena 				BUS_SPACE_MAXADDR,	/* highaddr */
51512d1d418eSSumit Saxena 				NULL, NULL,		/* filter, filterarg */
51522d1d418eSSumit Saxena 				mem_desc->size,		/* maxsize */
51532d1d418eSSumit Saxena 				1,			/* nsegments */
51542d1d418eSSumit Saxena 				mem_desc->size,		/* maxsegsize */
51552d1d418eSSumit Saxena 				0,			/* flags */
51562d1d418eSSumit Saxena 				NULL, NULL,		/* lockfunc, lockarg */
51572d1d418eSSumit Saxena 				&mem_desc->tag)) {
51582d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n");
51592d1d418eSSumit Saxena 		goto out_failed;
51602d1d418eSSumit Saxena 	}
51612d1d418eSSumit Saxena 
51622d1d418eSSumit Saxena 	if (bus_dmamem_alloc(mem_desc->tag, (void **)&mem_desc->addr,
51632d1d418eSSumit Saxena 	    BUS_DMA_NOWAIT, &mem_desc->dmamap)) {
51642d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n");
51652d1d418eSSumit Saxena 		goto out_failed;
51662d1d418eSSumit Saxena 	}
51672d1d418eSSumit Saxena 	bzero(mem_desc->addr, mem_desc->size);
51682d1d418eSSumit Saxena 	bus_dmamap_load(mem_desc->tag, mem_desc->dmamap, mem_desc->addr, mem_desc->size,
51692d1d418eSSumit Saxena 	    mpi3mr_memaddr_cb, &mem_desc->dma_addr, 0);
51702d1d418eSSumit Saxena 
51712d1d418eSSumit Saxena 	if (!mem_desc->addr)
51722d1d418eSSumit Saxena 		goto out_failed;
51732d1d418eSSumit Saxena 
51742d1d418eSSumit Saxena 	sc->ioctl_sges_allocated = true;
51752d1d418eSSumit Saxena 
51762d1d418eSSumit Saxena 	return;
51772d1d418eSSumit Saxena out_failed:
51782d1d418eSSumit Saxena 	printf("cannot allocate DMA memory for the mpt commands"
51792d1d418eSSumit Saxena 	    "  from the applications, application interface for MPT command is disabled\n");
51802d1d418eSSumit Saxena 	mpi3mr_free_ioctl_dma_memory(sc);
51812d1d418eSSumit Saxena }
51822d1d418eSSumit Saxena 
51832d1d418eSSumit Saxena void
51842d1d418eSSumit Saxena mpi3mr_destory_mtx(struct mpi3mr_softc *sc)
51852d1d418eSSumit Saxena {
51862d1d418eSSumit Saxena 	int i;
51872d1d418eSSumit Saxena 	struct mpi3mr_op_req_queue *op_req_q;
51882d1d418eSSumit Saxena 	struct mpi3mr_op_reply_queue *op_reply_q;
51892d1d418eSSumit Saxena 
51902d1d418eSSumit Saxena 	if (sc->admin_reply) {
51912d1d418eSSumit Saxena 		if (mtx_initialized(&sc->admin_reply_lock))
51922d1d418eSSumit Saxena 			mtx_destroy(&sc->admin_reply_lock);
51932d1d418eSSumit Saxena 	}
51942d1d418eSSumit Saxena 
51952d1d418eSSumit Saxena 	if (sc->op_reply_q) {
51962d1d418eSSumit Saxena 		for(i = 0; i < sc->num_queues; i++) {
51972d1d418eSSumit Saxena 			op_reply_q = sc->op_reply_q + i;
51982d1d418eSSumit Saxena 			if (mtx_initialized(&op_reply_q->q_lock))
51992d1d418eSSumit Saxena 				mtx_destroy(&op_reply_q->q_lock);
52002d1d418eSSumit Saxena 		}
52012d1d418eSSumit Saxena 	}
52022d1d418eSSumit Saxena 
52032d1d418eSSumit Saxena 	if (sc->op_req_q) {
52042d1d418eSSumit Saxena 		for(i = 0; i < sc->num_queues; i++) {
52052d1d418eSSumit Saxena 			op_req_q = sc->op_req_q + i;
52062d1d418eSSumit Saxena 			if (mtx_initialized(&op_req_q->q_lock))
52072d1d418eSSumit Saxena 				mtx_destroy(&op_req_q->q_lock);
52082d1d418eSSumit Saxena 		}
52092d1d418eSSumit Saxena 	}
52102d1d418eSSumit Saxena 
52112d1d418eSSumit Saxena 	if (mtx_initialized(&sc->init_cmds.completion.lock))
52122d1d418eSSumit Saxena 		mtx_destroy(&sc->init_cmds.completion.lock);
52132d1d418eSSumit Saxena 
52142d1d418eSSumit Saxena 	if (mtx_initialized(&sc->ioctl_cmds.completion.lock))
52152d1d418eSSumit Saxena 		mtx_destroy(&sc->ioctl_cmds.completion.lock);
52162d1d418eSSumit Saxena 
52172d1d418eSSumit Saxena 	if (mtx_initialized(&sc->host_tm_cmds.completion.lock))
52182d1d418eSSumit Saxena 		mtx_destroy(&sc->host_tm_cmds.completion.lock);
52192d1d418eSSumit Saxena 
52202d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
52212d1d418eSSumit Saxena 		if (mtx_initialized(&sc->dev_rmhs_cmds[i].completion.lock))
52222d1d418eSSumit Saxena 			mtx_destroy(&sc->dev_rmhs_cmds[i].completion.lock);
52232d1d418eSSumit Saxena 	}
52242d1d418eSSumit Saxena 
52252d1d418eSSumit Saxena 	if (mtx_initialized(&sc->reset_mutex))
52262d1d418eSSumit Saxena 		mtx_destroy(&sc->reset_mutex);
52272d1d418eSSumit Saxena 
52282d1d418eSSumit Saxena 	if (mtx_initialized(&sc->target_lock))
52292d1d418eSSumit Saxena 		mtx_destroy(&sc->target_lock);
52302d1d418eSSumit Saxena 
52312d1d418eSSumit Saxena 	if (mtx_initialized(&sc->fwevt_lock))
52322d1d418eSSumit Saxena 		mtx_destroy(&sc->fwevt_lock);
52332d1d418eSSumit Saxena 
52342d1d418eSSumit Saxena 	if (mtx_initialized(&sc->cmd_pool_lock))
52352d1d418eSSumit Saxena 		mtx_destroy(&sc->cmd_pool_lock);
52362d1d418eSSumit Saxena 
52372d1d418eSSumit Saxena 	if (mtx_initialized(&sc->reply_free_q_lock))
52382d1d418eSSumit Saxena 		mtx_destroy(&sc->reply_free_q_lock);
52392d1d418eSSumit Saxena 
52402d1d418eSSumit Saxena 	if (mtx_initialized(&sc->sense_buf_q_lock))
52412d1d418eSSumit Saxena 		mtx_destroy(&sc->sense_buf_q_lock);
52422d1d418eSSumit Saxena 
52432d1d418eSSumit Saxena 	if (mtx_initialized(&sc->chain_buf_lock))
52442d1d418eSSumit Saxena 		mtx_destroy(&sc->chain_buf_lock);
52452d1d418eSSumit Saxena 
52462d1d418eSSumit Saxena 	if (mtx_initialized(&sc->admin_req_lock))
52472d1d418eSSumit Saxena 		mtx_destroy(&sc->admin_req_lock);
52482d1d418eSSumit Saxena 
52492d1d418eSSumit Saxena 	if (mtx_initialized(&sc->mpi3mr_mtx))
52502d1d418eSSumit Saxena 		mtx_destroy(&sc->mpi3mr_mtx);
52512d1d418eSSumit Saxena }
52522d1d418eSSumit Saxena 
52532d1d418eSSumit Saxena /**
52542d1d418eSSumit Saxena  * mpi3mr_free_mem - Freeup adapter level data structures
52552d1d418eSSumit Saxena  * @sc: Adapter reference
52562d1d418eSSumit Saxena  *
52572d1d418eSSumit Saxena  * Return: Nothing.
52582d1d418eSSumit Saxena  */
52592d1d418eSSumit Saxena void
52602d1d418eSSumit Saxena mpi3mr_free_mem(struct mpi3mr_softc *sc)
52612d1d418eSSumit Saxena {
52622d1d418eSSumit Saxena 	int i;
52632d1d418eSSumit Saxena 	struct mpi3mr_op_req_queue *op_req_q;
52642d1d418eSSumit Saxena 	struct mpi3mr_op_reply_queue *op_reply_q;
52652d1d418eSSumit Saxena 	struct mpi3mr_irq_context *irq_ctx;
52662d1d418eSSumit Saxena 
52672d1d418eSSumit Saxena 	if (sc->cmd_list) {
52682d1d418eSSumit Saxena 		for (i = 0; i < sc->max_host_ios; i++) {
52692d1d418eSSumit Saxena 			free(sc->cmd_list[i], M_MPI3MR);
52702d1d418eSSumit Saxena 		}
52712d1d418eSSumit Saxena 		free(sc->cmd_list, M_MPI3MR);
52722d1d418eSSumit Saxena 		sc->cmd_list = NULL;
52732d1d418eSSumit Saxena 	}
52742d1d418eSSumit Saxena 
52752d1d418eSSumit Saxena 	if (sc->pel_seq_number && sc->pel_seq_number_dma) {
52762d1d418eSSumit Saxena 		bus_dmamap_unload(sc->pel_seq_num_dmatag, sc->pel_seq_num_dmamap);
52772d1d418eSSumit Saxena 		bus_dmamem_free(sc->pel_seq_num_dmatag, sc->pel_seq_number, sc->pel_seq_num_dmamap);
52782d1d418eSSumit Saxena 		sc->pel_seq_number = NULL;
52792d1d418eSSumit Saxena 		if (sc->pel_seq_num_dmatag != NULL)
52802d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->pel_seq_num_dmatag);
52812d1d418eSSumit Saxena 	}
52822d1d418eSSumit Saxena 
52832d1d418eSSumit Saxena 	if (sc->throttle_groups) {
52842d1d418eSSumit Saxena 		free(sc->throttle_groups, M_MPI3MR);
52852d1d418eSSumit Saxena 		sc->throttle_groups = NULL;
52862d1d418eSSumit Saxena 	}
52872d1d418eSSumit Saxena 
52882d1d418eSSumit Saxena 	/* Free up operational queues*/
52892d1d418eSSumit Saxena 	if (sc->op_req_q) {
52902d1d418eSSumit Saxena 		for (i = 0; i < sc->num_queues; i++) {
52912d1d418eSSumit Saxena 			op_req_q = sc->op_req_q + i;
52922d1d418eSSumit Saxena 			if (op_req_q->q_base && op_req_q->q_base_phys) {
52932d1d418eSSumit Saxena 				bus_dmamap_unload(op_req_q->q_base_tag, op_req_q->q_base_dmamap);
52942d1d418eSSumit Saxena 				bus_dmamem_free(op_req_q->q_base_tag, op_req_q->q_base, op_req_q->q_base_dmamap);
52952d1d418eSSumit Saxena 				op_req_q->q_base = NULL;
52962d1d418eSSumit Saxena 				if (op_req_q->q_base_tag != NULL)
52972d1d418eSSumit Saxena 					bus_dma_tag_destroy(op_req_q->q_base_tag);
52982d1d418eSSumit Saxena 			}
52992d1d418eSSumit Saxena 		}
53002d1d418eSSumit Saxena 		free(sc->op_req_q, M_MPI3MR);
53012d1d418eSSumit Saxena 		sc->op_req_q = NULL;
53022d1d418eSSumit Saxena 	}
53032d1d418eSSumit Saxena 
53042d1d418eSSumit Saxena 	if (sc->op_reply_q) {
53052d1d418eSSumit Saxena 		for (i = 0; i < sc->num_queues; i++) {
53062d1d418eSSumit Saxena 			op_reply_q = sc->op_reply_q + i;
53072d1d418eSSumit Saxena 			if (op_reply_q->q_base && op_reply_q->q_base_phys) {
53082d1d418eSSumit Saxena 				bus_dmamap_unload(op_reply_q->q_base_tag, op_reply_q->q_base_dmamap);
53092d1d418eSSumit Saxena 				bus_dmamem_free(op_reply_q->q_base_tag, op_reply_q->q_base, op_reply_q->q_base_dmamap);
53102d1d418eSSumit Saxena 				op_reply_q->q_base = NULL;
53112d1d418eSSumit Saxena 				if (op_reply_q->q_base_tag != NULL)
53122d1d418eSSumit Saxena 					bus_dma_tag_destroy(op_reply_q->q_base_tag);
53132d1d418eSSumit Saxena 			}
53142d1d418eSSumit Saxena 		}
53152d1d418eSSumit Saxena 		free(sc->op_reply_q, M_MPI3MR);
53162d1d418eSSumit Saxena 		sc->op_reply_q = NULL;
53172d1d418eSSumit Saxena 	}
53182d1d418eSSumit Saxena 
53192d1d418eSSumit Saxena 	/* Free up chain buffers*/
53202d1d418eSSumit Saxena 	if (sc->chain_sgl_list) {
53212d1d418eSSumit Saxena 		for (i = 0; i < sc->chain_buf_count; i++) {
53222d1d418eSSumit Saxena 			if (sc->chain_sgl_list[i].buf && sc->chain_sgl_list[i].buf_phys) {
53232d1d418eSSumit Saxena 				bus_dmamap_unload(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf_dmamap);
53242d1d418eSSumit Saxena 				bus_dmamem_free(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf,
53252d1d418eSSumit Saxena 						sc->chain_sgl_list[i].buf_dmamap);
53262d1d418eSSumit Saxena 				sc->chain_sgl_list[i].buf = NULL;
53272d1d418eSSumit Saxena 			}
53282d1d418eSSumit Saxena 		}
53292d1d418eSSumit Saxena 		if (sc->chain_sgl_list_tag != NULL)
53302d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->chain_sgl_list_tag);
53312d1d418eSSumit Saxena 		free(sc->chain_sgl_list, M_MPI3MR);
53322d1d418eSSumit Saxena 		sc->chain_sgl_list = NULL;
53332d1d418eSSumit Saxena 	}
53342d1d418eSSumit Saxena 
53352d1d418eSSumit Saxena 	if (sc->chain_bitmap) {
53362d1d418eSSumit Saxena 		free(sc->chain_bitmap, M_MPI3MR);
53372d1d418eSSumit Saxena 		sc->chain_bitmap = NULL;
53382d1d418eSSumit Saxena 	}
53392d1d418eSSumit Saxena 
53402d1d418eSSumit Saxena 	for (i = 0; i < sc->msix_count; i++) {
53412d1d418eSSumit Saxena 		irq_ctx = sc->irq_ctx + i;
53422d1d418eSSumit Saxena 		if (irq_ctx)
53432d1d418eSSumit Saxena 			irq_ctx->op_reply_q = NULL;
53442d1d418eSSumit Saxena 	}
53452d1d418eSSumit Saxena 
53462d1d418eSSumit Saxena 	/* Free reply_buf_tag */
53472d1d418eSSumit Saxena 	if (sc->reply_buf && sc->reply_buf_phys) {
53482d1d418eSSumit Saxena 		bus_dmamap_unload(sc->reply_buf_tag, sc->reply_buf_dmamap);
53492d1d418eSSumit Saxena 		bus_dmamem_free(sc->reply_buf_tag, sc->reply_buf,
53502d1d418eSSumit Saxena 				sc->reply_buf_dmamap);
53512d1d418eSSumit Saxena 		sc->reply_buf = NULL;
53522d1d418eSSumit Saxena 		if (sc->reply_buf_tag != NULL)
53532d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->reply_buf_tag);
53542d1d418eSSumit Saxena 	}
53552d1d418eSSumit Saxena 
53562d1d418eSSumit Saxena 	/* Free reply_free_q_tag */
53572d1d418eSSumit Saxena 	if (sc->reply_free_q && sc->reply_free_q_phys) {
53582d1d418eSSumit Saxena 		bus_dmamap_unload(sc->reply_free_q_tag, sc->reply_free_q_dmamap);
53592d1d418eSSumit Saxena 		bus_dmamem_free(sc->reply_free_q_tag, sc->reply_free_q,
53602d1d418eSSumit Saxena 				sc->reply_free_q_dmamap);
53612d1d418eSSumit Saxena 		sc->reply_free_q = NULL;
53622d1d418eSSumit Saxena 		if (sc->reply_free_q_tag != NULL)
53632d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->reply_free_q_tag);
53642d1d418eSSumit Saxena 	}
53652d1d418eSSumit Saxena 
53662d1d418eSSumit Saxena 	/* Free sense_buf_tag */
53672d1d418eSSumit Saxena 	if (sc->sense_buf && sc->sense_buf_phys) {
53682d1d418eSSumit Saxena 		bus_dmamap_unload(sc->sense_buf_tag, sc->sense_buf_dmamap);
53692d1d418eSSumit Saxena 		bus_dmamem_free(sc->sense_buf_tag, sc->sense_buf,
53702d1d418eSSumit Saxena 				sc->sense_buf_dmamap);
53712d1d418eSSumit Saxena 		sc->sense_buf = NULL;
53722d1d418eSSumit Saxena 		if (sc->sense_buf_tag != NULL)
53732d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->sense_buf_tag);
53742d1d418eSSumit Saxena 	}
53752d1d418eSSumit Saxena 
53762d1d418eSSumit Saxena 	/* Free sense_buf_q_tag */
53772d1d418eSSumit Saxena 	if (sc->sense_buf_q && sc->sense_buf_q_phys) {
53782d1d418eSSumit Saxena 		bus_dmamap_unload(sc->sense_buf_q_tag, sc->sense_buf_q_dmamap);
53792d1d418eSSumit Saxena 		bus_dmamem_free(sc->sense_buf_q_tag, sc->sense_buf_q,
53802d1d418eSSumit Saxena 				sc->sense_buf_q_dmamap);
53812d1d418eSSumit Saxena 		sc->sense_buf_q = NULL;
53822d1d418eSSumit Saxena 		if (sc->sense_buf_q_tag != NULL)
53832d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->sense_buf_q_tag);
53842d1d418eSSumit Saxena 	}
53852d1d418eSSumit Saxena 
53862d1d418eSSumit Saxena 	/* Free up internal(non-IO) commands*/
53872d1d418eSSumit Saxena 	if (sc->init_cmds.reply) {
53882d1d418eSSumit Saxena 		free(sc->init_cmds.reply, M_MPI3MR);
53892d1d418eSSumit Saxena 		sc->init_cmds.reply = NULL;
53902d1d418eSSumit Saxena 	}
53912d1d418eSSumit Saxena 
53922d1d418eSSumit Saxena 	if (sc->ioctl_cmds.reply) {
53932d1d418eSSumit Saxena 		free(sc->ioctl_cmds.reply, M_MPI3MR);
53942d1d418eSSumit Saxena 		sc->ioctl_cmds.reply = NULL;
53952d1d418eSSumit Saxena 	}
53962d1d418eSSumit Saxena 
53972d1d418eSSumit Saxena 	if (sc->pel_cmds.reply) {
53982d1d418eSSumit Saxena 		free(sc->pel_cmds.reply, M_MPI3MR);
53992d1d418eSSumit Saxena 		sc->pel_cmds.reply = NULL;
54002d1d418eSSumit Saxena 	}
54012d1d418eSSumit Saxena 
54022d1d418eSSumit Saxena 	if (sc->pel_abort_cmd.reply) {
54032d1d418eSSumit Saxena 		free(sc->pel_abort_cmd.reply, M_MPI3MR);
54042d1d418eSSumit Saxena 		sc->pel_abort_cmd.reply = NULL;
54052d1d418eSSumit Saxena 	}
54062d1d418eSSumit Saxena 
54072d1d418eSSumit Saxena 	if (sc->host_tm_cmds.reply) {
54082d1d418eSSumit Saxena 		free(sc->host_tm_cmds.reply, M_MPI3MR);
54092d1d418eSSumit Saxena 		sc->host_tm_cmds.reply = NULL;
54102d1d418eSSumit Saxena 	}
54112d1d418eSSumit Saxena 
54122d1d418eSSumit Saxena 	if (sc->log_data_buffer) {
54132d1d418eSSumit Saxena 		free(sc->log_data_buffer, M_MPI3MR);
54142d1d418eSSumit Saxena 		sc->log_data_buffer = NULL;
54152d1d418eSSumit Saxena 	}
54162d1d418eSSumit Saxena 
54172d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
54182d1d418eSSumit Saxena 		if (sc->dev_rmhs_cmds[i].reply) {
54192d1d418eSSumit Saxena 			free(sc->dev_rmhs_cmds[i].reply, M_MPI3MR);
54202d1d418eSSumit Saxena 			sc->dev_rmhs_cmds[i].reply = NULL;
54212d1d418eSSumit Saxena 		}
54222d1d418eSSumit Saxena 	}
54232d1d418eSSumit Saxena 
54242d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
54252d1d418eSSumit Saxena 		if (sc->evtack_cmds[i].reply) {
54262d1d418eSSumit Saxena 			free(sc->evtack_cmds[i].reply, M_MPI3MR);
54272d1d418eSSumit Saxena 			sc->evtack_cmds[i].reply = NULL;
54282d1d418eSSumit Saxena 		}
54292d1d418eSSumit Saxena 	}
54302d1d418eSSumit Saxena 
54312d1d418eSSumit Saxena 	if (sc->removepend_bitmap) {
54322d1d418eSSumit Saxena 		free(sc->removepend_bitmap, M_MPI3MR);
54332d1d418eSSumit Saxena 		sc->removepend_bitmap = NULL;
54342d1d418eSSumit Saxena 	}
54352d1d418eSSumit Saxena 
54362d1d418eSSumit Saxena 	if (sc->devrem_bitmap) {
54372d1d418eSSumit Saxena 		free(sc->devrem_bitmap, M_MPI3MR);
54382d1d418eSSumit Saxena 		sc->devrem_bitmap = NULL;
54392d1d418eSSumit Saxena 	}
54402d1d418eSSumit Saxena 
54412d1d418eSSumit Saxena 	if (sc->evtack_cmds_bitmap) {
54422d1d418eSSumit Saxena 		free(sc->evtack_cmds_bitmap, M_MPI3MR);
54432d1d418eSSumit Saxena 		sc->evtack_cmds_bitmap = NULL;
54442d1d418eSSumit Saxena 	}
54452d1d418eSSumit Saxena 
54462d1d418eSSumit Saxena 	/* Free Admin reply*/
54472d1d418eSSumit Saxena 	if (sc->admin_reply && sc->admin_reply_phys) {
54482d1d418eSSumit Saxena 		bus_dmamap_unload(sc->admin_reply_tag, sc->admin_reply_dmamap);
54492d1d418eSSumit Saxena 		bus_dmamem_free(sc->admin_reply_tag, sc->admin_reply,
54502d1d418eSSumit Saxena 				sc->admin_reply_dmamap);
54512d1d418eSSumit Saxena 		sc->admin_reply = NULL;
54522d1d418eSSumit Saxena 		if (sc->admin_reply_tag != NULL)
54532d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->admin_reply_tag);
54542d1d418eSSumit Saxena 	}
54552d1d418eSSumit Saxena 
54562d1d418eSSumit Saxena 	/* Free Admin request*/
54572d1d418eSSumit Saxena 	if (sc->admin_req && sc->admin_req_phys) {
54582d1d418eSSumit Saxena 		bus_dmamap_unload(sc->admin_req_tag, sc->admin_req_dmamap);
54592d1d418eSSumit Saxena 		bus_dmamem_free(sc->admin_req_tag, sc->admin_req,
54602d1d418eSSumit Saxena 				sc->admin_req_dmamap);
54612d1d418eSSumit Saxena 		sc->admin_req = NULL;
54622d1d418eSSumit Saxena 		if (sc->admin_req_tag != NULL)
54632d1d418eSSumit Saxena 			bus_dma_tag_destroy(sc->admin_req_tag);
54642d1d418eSSumit Saxena 	}
54652d1d418eSSumit Saxena 	mpi3mr_free_ioctl_dma_memory(sc);
54662d1d418eSSumit Saxena 
54672d1d418eSSumit Saxena }
54682d1d418eSSumit Saxena 
54692d1d418eSSumit Saxena /**
54702d1d418eSSumit Saxena  * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command
54712d1d418eSSumit Saxena  * @sc: Adapter instance reference
54722d1d418eSSumit Saxena  * @cmdptr: Internal command tracker
54732d1d418eSSumit Saxena  *
54742d1d418eSSumit Saxena  * Complete an internal driver commands with state indicating it
54752d1d418eSSumit Saxena  * is completed due to reset.
54762d1d418eSSumit Saxena  *
54772d1d418eSSumit Saxena  * Return: Nothing.
54782d1d418eSSumit Saxena  */
54792d1d418eSSumit Saxena static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_softc *sc,
54802d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdptr)
54812d1d418eSSumit Saxena {
54822d1d418eSSumit Saxena 	if (cmdptr->state & MPI3MR_CMD_PENDING) {
54832d1d418eSSumit Saxena 		cmdptr->state |= MPI3MR_CMD_RESET;
54842d1d418eSSumit Saxena 		cmdptr->state &= ~MPI3MR_CMD_PENDING;
54852d1d418eSSumit Saxena 		if (cmdptr->is_waiting) {
54862d1d418eSSumit Saxena 			complete(&cmdptr->completion);
54872d1d418eSSumit Saxena 			cmdptr->is_waiting = 0;
54882d1d418eSSumit Saxena 		} else if (cmdptr->callback)
54892d1d418eSSumit Saxena 			cmdptr->callback(sc, cmdptr);
54902d1d418eSSumit Saxena 	}
54912d1d418eSSumit Saxena }
54922d1d418eSSumit Saxena 
54932d1d418eSSumit Saxena /**
54942d1d418eSSumit Saxena  * mpi3mr_flush_drv_cmds - Flush internal driver commands
54952d1d418eSSumit Saxena  * @sc: Adapter instance reference
54962d1d418eSSumit Saxena  *
54972d1d418eSSumit Saxena  * Flush all internal driver commands post reset
54982d1d418eSSumit Saxena  *
54992d1d418eSSumit Saxena  * Return: Nothing.
55002d1d418eSSumit Saxena  */
55012d1d418eSSumit Saxena static void mpi3mr_flush_drv_cmds(struct mpi3mr_softc *sc)
55022d1d418eSSumit Saxena {
55032d1d418eSSumit Saxena 	int i = 0;
55042d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *cmdptr;
55052d1d418eSSumit Saxena 
55062d1d418eSSumit Saxena 	cmdptr = &sc->init_cmds;
55072d1d418eSSumit Saxena 	mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
55082d1d418eSSumit Saxena 
55092d1d418eSSumit Saxena 	cmdptr = &sc->ioctl_cmds;
55102d1d418eSSumit Saxena 	mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
55112d1d418eSSumit Saxena 
55122d1d418eSSumit Saxena 	cmdptr = &sc->host_tm_cmds;
55132d1d418eSSumit Saxena 	mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
55142d1d418eSSumit Saxena 
55152d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
55162d1d418eSSumit Saxena 		cmdptr = &sc->dev_rmhs_cmds[i];
55172d1d418eSSumit Saxena 		mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
55182d1d418eSSumit Saxena 	}
55192d1d418eSSumit Saxena 
55202d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
55212d1d418eSSumit Saxena 		cmdptr = &sc->evtack_cmds[i];
55222d1d418eSSumit Saxena 		mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
55232d1d418eSSumit Saxena 	}
55242d1d418eSSumit Saxena 
55252d1d418eSSumit Saxena 	cmdptr = &sc->pel_cmds;
55262d1d418eSSumit Saxena 	mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
55272d1d418eSSumit Saxena 
55282d1d418eSSumit Saxena 	cmdptr = &sc->pel_abort_cmd;
55292d1d418eSSumit Saxena 	mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
55302d1d418eSSumit Saxena }
55312d1d418eSSumit Saxena 
55322d1d418eSSumit Saxena 
55332d1d418eSSumit Saxena /**
55342d1d418eSSumit Saxena  * mpi3mr_memset_buffers - memset memory for a controller
55352d1d418eSSumit Saxena  * @sc: Adapter instance reference
55362d1d418eSSumit Saxena  *
55372d1d418eSSumit Saxena  * clear all the memory allocated for a controller, typically
55382d1d418eSSumit Saxena  * called post reset to reuse the memory allocated during the
55392d1d418eSSumit Saxena  * controller init.
55402d1d418eSSumit Saxena  *
55412d1d418eSSumit Saxena  * Return: Nothing.
55422d1d418eSSumit Saxena  */
55432d1d418eSSumit Saxena static void mpi3mr_memset_buffers(struct mpi3mr_softc *sc)
55442d1d418eSSumit Saxena {
55452d1d418eSSumit Saxena 	U16 i;
55462d1d418eSSumit Saxena 	struct mpi3mr_throttle_group_info *tg;
55472d1d418eSSumit Saxena 
55482d1d418eSSumit Saxena 	memset(sc->admin_req, 0, sc->admin_req_q_sz);
55492d1d418eSSumit Saxena 	memset(sc->admin_reply, 0, sc->admin_reply_q_sz);
55502d1d418eSSumit Saxena 
55512d1d418eSSumit Saxena 	memset(sc->init_cmds.reply, 0, sc->reply_sz);
55522d1d418eSSumit Saxena 	memset(sc->ioctl_cmds.reply, 0, sc->reply_sz);
55532d1d418eSSumit Saxena 	memset(sc->host_tm_cmds.reply, 0, sc->reply_sz);
55542d1d418eSSumit Saxena 	memset(sc->pel_cmds.reply, 0, sc->reply_sz);
55552d1d418eSSumit Saxena 	memset(sc->pel_abort_cmd.reply, 0, sc->reply_sz);
55562d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
55572d1d418eSSumit Saxena 		memset(sc->dev_rmhs_cmds[i].reply, 0, sc->reply_sz);
55582d1d418eSSumit Saxena 	for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++)
55592d1d418eSSumit Saxena 		memset(sc->evtack_cmds[i].reply, 0, sc->reply_sz);
55602d1d418eSSumit Saxena 	memset(sc->removepend_bitmap, 0, sc->dev_handle_bitmap_sz);
55612d1d418eSSumit Saxena 	memset(sc->devrem_bitmap, 0, sc->devrem_bitmap_sz);
55622d1d418eSSumit Saxena 	memset(sc->evtack_cmds_bitmap, 0, sc->evtack_cmds_bitmap_sz);
55632d1d418eSSumit Saxena 
55642d1d418eSSumit Saxena 	for (i = 0; i < sc->num_queues; i++) {
55652d1d418eSSumit Saxena 		sc->op_reply_q[i].qid = 0;
55662d1d418eSSumit Saxena 		sc->op_reply_q[i].ci = 0;
55672d1d418eSSumit Saxena 		sc->op_reply_q[i].num_replies = 0;
55682d1d418eSSumit Saxena 		sc->op_reply_q[i].ephase = 0;
55692d1d418eSSumit Saxena 		mpi3mr_atomic_set(&sc->op_reply_q[i].pend_ios, 0);
55702d1d418eSSumit Saxena 		memset(sc->op_reply_q[i].q_base, 0, sc->op_reply_q[i].qsz);
55712d1d418eSSumit Saxena 
55722d1d418eSSumit Saxena 		sc->op_req_q[i].ci = 0;
55732d1d418eSSumit Saxena 		sc->op_req_q[i].pi = 0;
55742d1d418eSSumit Saxena 		sc->op_req_q[i].num_reqs = 0;
55752d1d418eSSumit Saxena 		sc->op_req_q[i].qid = 0;
55762d1d418eSSumit Saxena 		sc->op_req_q[i].reply_qid = 0;
55772d1d418eSSumit Saxena 		memset(sc->op_req_q[i].q_base, 0, sc->op_req_q[i].qsz);
55782d1d418eSSumit Saxena 	}
55792d1d418eSSumit Saxena 
55802d1d418eSSumit Saxena 	mpi3mr_atomic_set(&sc->pend_large_data_sz, 0);
55812d1d418eSSumit Saxena 	if (sc->throttle_groups) {
55822d1d418eSSumit Saxena 		tg = sc->throttle_groups;
55832d1d418eSSumit Saxena 		for (i = 0; i < sc->num_io_throttle_group; i++, tg++) {
55842d1d418eSSumit Saxena 			tg->id = 0;
55852d1d418eSSumit Saxena 			tg->fw_qd = 0;
55862d1d418eSSumit Saxena 			tg->modified_qd = 0;
55872d1d418eSSumit Saxena 			tg->io_divert= 0;
55882d1d418eSSumit Saxena 			tg->high = 0;
55892d1d418eSSumit Saxena 			tg->low = 0;
55902d1d418eSSumit Saxena 			mpi3mr_atomic_set(&tg->pend_large_data_sz, 0);
55912d1d418eSSumit Saxena 		}
55922d1d418eSSumit Saxena  	}
55932d1d418eSSumit Saxena }
55942d1d418eSSumit Saxena 
55952d1d418eSSumit Saxena /**
55962d1d418eSSumit Saxena  * mpi3mr_invalidate_devhandles -Invalidate device handles
55972d1d418eSSumit Saxena  * @sc: Adapter instance reference
55982d1d418eSSumit Saxena  *
55992d1d418eSSumit Saxena  * Invalidate the device handles in the target device structures
56002d1d418eSSumit Saxena  * . Called post reset prior to reinitializing the controller.
56012d1d418eSSumit Saxena  *
56022d1d418eSSumit Saxena  * Return: Nothing.
56032d1d418eSSumit Saxena  */
56042d1d418eSSumit Saxena static void mpi3mr_invalidate_devhandles(struct mpi3mr_softc *sc)
56052d1d418eSSumit Saxena {
56062d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
56072d1d418eSSumit Saxena 
56082d1d418eSSumit Saxena 	mtx_lock_spin(&sc->target_lock);
56092d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) {
56102d1d418eSSumit Saxena 		if (target) {
56112d1d418eSSumit Saxena 			target->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
56122d1d418eSSumit Saxena 			target->io_throttle_enabled = 0;
56132d1d418eSSumit Saxena 			target->io_divert = 0;
56142d1d418eSSumit Saxena 			target->throttle_group = NULL;
56152d1d418eSSumit Saxena 		}
56162d1d418eSSumit Saxena 	}
56172d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->target_lock);
56182d1d418eSSumit Saxena }
56192d1d418eSSumit Saxena 
56202d1d418eSSumit Saxena /**
56212d1d418eSSumit Saxena  * mpi3mr_rfresh_tgtdevs - Refresh target device exposure
56222d1d418eSSumit Saxena  * @sc: Adapter instance reference
56232d1d418eSSumit Saxena  *
56242d1d418eSSumit Saxena  * This is executed post controller reset to identify any
56252d1d418eSSumit Saxena  * missing devices during reset and remove from the upper layers
56262d1d418eSSumit Saxena  * or expose any newly detected device to the upper layers.
56272d1d418eSSumit Saxena  *
56282d1d418eSSumit Saxena  * Return: Nothing.
56292d1d418eSSumit Saxena  */
56302d1d418eSSumit Saxena 
56312d1d418eSSumit Saxena static void mpi3mr_rfresh_tgtdevs(struct mpi3mr_softc *sc)
56322d1d418eSSumit Saxena {
56332d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
56342d1d418eSSumit Saxena 	struct mpi3mr_target *target_temp = NULL;
56352d1d418eSSumit Saxena 
56362d1d418eSSumit Saxena 	TAILQ_FOREACH_SAFE(target, &sc->cam_sc->tgt_list, tgt_next, target_temp) {
56372d1d418eSSumit Saxena 		if (target->dev_handle == MPI3MR_INVALID_DEV_HANDLE) {
56382d1d418eSSumit Saxena 			if (target->exposed_to_os)
56392d1d418eSSumit Saxena 				mpi3mr_remove_device_from_os(sc, target->dev_handle);
56402d1d418eSSumit Saxena 			mpi3mr_remove_device_from_list(sc, target, true);
56412d1d418eSSumit Saxena 		}
56422d1d418eSSumit Saxena 	}
56432d1d418eSSumit Saxena 
56442d1d418eSSumit Saxena 	TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) {
56452d1d418eSSumit Saxena 		if ((target->dev_handle != MPI3MR_INVALID_DEV_HANDLE) &&
56462d1d418eSSumit Saxena 		    !target->is_hidden && !target->exposed_to_os) {
56472d1d418eSSumit Saxena 			mpi3mr_add_device(sc, target->per_id);
56482d1d418eSSumit Saxena 		}
56492d1d418eSSumit Saxena 	}
56502d1d418eSSumit Saxena 
56512d1d418eSSumit Saxena }
56522d1d418eSSumit Saxena 
56532d1d418eSSumit Saxena static void mpi3mr_flush_io(struct mpi3mr_softc *sc)
56542d1d418eSSumit Saxena {
56552d1d418eSSumit Saxena 	int i;
56562d1d418eSSumit Saxena 	struct mpi3mr_cmd *cmd = NULL;
56572d1d418eSSumit Saxena 	union ccb *ccb = NULL;
56582d1d418eSSumit Saxena 
56592d1d418eSSumit Saxena 	for (i = 0; i < sc->max_host_ios; i++) {
56602d1d418eSSumit Saxena 		cmd = sc->cmd_list[i];
56612d1d418eSSumit Saxena 
56622d1d418eSSumit Saxena 		if (cmd && cmd->ccb) {
56632d1d418eSSumit Saxena 			if (cmd->callout_owner) {
56642d1d418eSSumit Saxena 				ccb = (union ccb *)(cmd->ccb);
56652d1d418eSSumit Saxena 				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
56662d1d418eSSumit Saxena 				mpi3mr_cmd_done(sc, cmd);
56672d1d418eSSumit Saxena 			} else {
56682d1d418eSSumit Saxena 				cmd->ccb = NULL;
56692d1d418eSSumit Saxena 				mpi3mr_release_command(cmd);
56702d1d418eSSumit Saxena 			}
56712d1d418eSSumit Saxena 		}
56722d1d418eSSumit Saxena 	}
56732d1d418eSSumit Saxena }
56742d1d418eSSumit Saxena /**
56752d1d418eSSumit Saxena  * mpi3mr_clear_reset_history - Clear reset history
56762d1d418eSSumit Saxena  * @sc: Adapter instance reference
56772d1d418eSSumit Saxena  *
56782d1d418eSSumit Saxena  * Write the reset history bit in IOC Status to clear the bit,
56792d1d418eSSumit Saxena  * if it is already set.
56802d1d418eSSumit Saxena  *
56812d1d418eSSumit Saxena  * Return: Nothing.
56822d1d418eSSumit Saxena  */
56832d1d418eSSumit Saxena static inline void mpi3mr_clear_reset_history(struct mpi3mr_softc *sc)
56842d1d418eSSumit Saxena {
56852d1d418eSSumit Saxena 	U32 ioc_status;
56862d1d418eSSumit Saxena 
56872d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
56882d1d418eSSumit Saxena 	if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
56892d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_STATUS_OFFSET, ioc_status);
56902d1d418eSSumit Saxena }
56912d1d418eSSumit Saxena 
56922d1d418eSSumit Saxena /**
56932d1d418eSSumit Saxena  * mpi3mr_set_diagsave - Set diag save bit for snapdump
56942d1d418eSSumit Saxena  * @sc: Adapter reference
56952d1d418eSSumit Saxena  *
56962d1d418eSSumit Saxena  * Set diag save bit in IOC configuration register to enable
56972d1d418eSSumit Saxena  * snapdump.
56982d1d418eSSumit Saxena  *
56992d1d418eSSumit Saxena  * Return: Nothing.
57002d1d418eSSumit Saxena  */
57012d1d418eSSumit Saxena static inline void mpi3mr_set_diagsave(struct mpi3mr_softc *sc)
57022d1d418eSSumit Saxena {
57032d1d418eSSumit Saxena 	U32 ioc_config;
57042d1d418eSSumit Saxena 
57052d1d418eSSumit Saxena 	ioc_config =
57062d1d418eSSumit Saxena 	    mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
57072d1d418eSSumit Saxena 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE;
57082d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
57092d1d418eSSumit Saxena }
57102d1d418eSSumit Saxena 
57112d1d418eSSumit Saxena /**
57122d1d418eSSumit Saxena  * mpi3mr_issue_reset - Issue reset to the controller
57132d1d418eSSumit Saxena  * @sc: Adapter reference
57142d1d418eSSumit Saxena  * @reset_type: Reset type
57152d1d418eSSumit Saxena  * @reset_reason: Reset reason code
57162d1d418eSSumit Saxena  *
57172d1d418eSSumit Saxena  * Unlock the host diagnostic registers and write the specific
57182d1d418eSSumit Saxena  * reset type to that, wait for reset acknowledgement from the
57192d1d418eSSumit Saxena  * controller, if the reset is not successful retry for the
57202d1d418eSSumit Saxena  * predefined number of times.
57212d1d418eSSumit Saxena  *
57222d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failure.
57232d1d418eSSumit Saxena  */
57242d1d418eSSumit Saxena static int mpi3mr_issue_reset(struct mpi3mr_softc *sc, U16 reset_type,
57252d1d418eSSumit Saxena 	U32 reset_reason)
57262d1d418eSSumit Saxena {
57272d1d418eSSumit Saxena 	int retval = -1;
57282d1d418eSSumit Saxena 	U8 unlock_retry_count = 0;
57292d1d418eSSumit Saxena 	U32 host_diagnostic, ioc_status, ioc_config;
57302d1d418eSSumit Saxena 	U32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
57312d1d418eSSumit Saxena 
57322d1d418eSSumit Saxena 	if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) &&
57332d1d418eSSumit Saxena 	    (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT))
57342d1d418eSSumit Saxena 		return retval;
57352d1d418eSSumit Saxena 	if (sc->unrecoverable)
57362d1d418eSSumit Saxena 		return retval;
57372d1d418eSSumit Saxena 
57382d1d418eSSumit Saxena 	if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) {
57392d1d418eSSumit Saxena 		retval = 0;
57402d1d418eSSumit Saxena 		return retval;
57412d1d418eSSumit Saxena 	}
57422d1d418eSSumit Saxena 
57432d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "%s reset due to %s(0x%x)\n",
57442d1d418eSSumit Saxena 	    mpi3mr_reset_type_name(reset_type),
57452d1d418eSSumit Saxena 	    mpi3mr_reset_rc_name(reset_reason), reset_reason);
57462d1d418eSSumit Saxena 
57472d1d418eSSumit Saxena 	mpi3mr_clear_reset_history(sc);
57482d1d418eSSumit Saxena 	do {
57492d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
57502d1d418eSSumit Saxena 		    "Write magic sequence to unlock host diag register (retry=%d)\n",
57512d1d418eSSumit Saxena 		    ++unlock_retry_count);
57522d1d418eSSumit Saxena 		if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) {
57532d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
57542d1d418eSSumit Saxena 			    "%s reset failed! due to host diag register unlock failure"
57552d1d418eSSumit Saxena 			    "host_diagnostic(0x%08x)\n", mpi3mr_reset_type_name(reset_type),
57562d1d418eSSumit Saxena 			    host_diagnostic);
57572d1d418eSSumit Saxena 			sc->unrecoverable = 1;
57582d1d418eSSumit Saxena 			return retval;
57592d1d418eSSumit Saxena 		}
57602d1d418eSSumit Saxena 
57612d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
57622d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH);
57632d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
57642d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST);
57652d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
57662d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND);
57672d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
57682d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD);
57692d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
57702d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH);
57712d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
57722d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH);
57732d1d418eSSumit Saxena 		mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
57742d1d418eSSumit Saxena 			MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH);
57752d1d418eSSumit Saxena 
57762d1d418eSSumit Saxena 		DELAY(1000); /* delay in usec */
57772d1d418eSSumit Saxena 		host_diagnostic = mpi3mr_regread(sc, MPI3_SYSIF_HOST_DIAG_OFFSET);
57782d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
57792d1d418eSSumit Saxena 		    "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n",
57802d1d418eSSumit Saxena 		    unlock_retry_count, host_diagnostic);
57812d1d418eSSumit Saxena 	} while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE));
57822d1d418eSSumit Saxena 
57832d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_SCRATCHPAD0_OFFSET, reset_reason);
57842d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_HOST_DIAG_OFFSET, host_diagnostic | reset_type);
57852d1d418eSSumit Saxena 
57862d1d418eSSumit Saxena 	if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) {
57872d1d418eSSumit Saxena 		do {
57882d1d418eSSumit Saxena 			ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
57892d1d418eSSumit Saxena 			if (ioc_status &
57902d1d418eSSumit Saxena 			    MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
57912d1d418eSSumit Saxena 				ioc_config =
57922d1d418eSSumit Saxena 				    mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
57932d1d418eSSumit Saxena 				if (mpi3mr_soft_reset_success(ioc_status,
57942d1d418eSSumit Saxena 				    ioc_config)) {
57952d1d418eSSumit Saxena 					mpi3mr_clear_reset_history(sc);
57962d1d418eSSumit Saxena 					retval = 0;
57972d1d418eSSumit Saxena 					break;
57982d1d418eSSumit Saxena 				}
57992d1d418eSSumit Saxena 			}
58002d1d418eSSumit Saxena 			DELAY(100 * 1000);
58012d1d418eSSumit Saxena 		} while (--timeout);
58022d1d418eSSumit Saxena 	} else if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT) {
58032d1d418eSSumit Saxena 		do {
58042d1d418eSSumit Saxena 			ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
58052d1d418eSSumit Saxena 			if (mpi3mr_diagfault_success(sc, ioc_status)) {
58062d1d418eSSumit Saxena 				retval = 0;
58072d1d418eSSumit Saxena 				break;
58082d1d418eSSumit Saxena 			}
58092d1d418eSSumit Saxena 			DELAY(100 * 1000);
58102d1d418eSSumit Saxena 		} while (--timeout);
58112d1d418eSSumit Saxena 	}
58122d1d418eSSumit Saxena 
58132d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET,
58142d1d418eSSumit Saxena 		MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND);
58152d1d418eSSumit Saxena 
58162d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
58172d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
58182d1d418eSSumit Saxena 
58192d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
58202d1d418eSSumit Saxena 	    "IOC Status/Config after %s reset is (0x%x)/(0x%x)\n",
58212d1d418eSSumit Saxena 	    !retval ? "successful":"failed", ioc_status,
58222d1d418eSSumit Saxena 	    ioc_config);
58232d1d418eSSumit Saxena 
58242d1d418eSSumit Saxena 	if (retval)
58252d1d418eSSumit Saxena 		sc->unrecoverable = 1;
58262d1d418eSSumit Saxena 
58272d1d418eSSumit Saxena 	return retval;
58282d1d418eSSumit Saxena }
58292d1d418eSSumit Saxena 
58302d1d418eSSumit Saxena inline void mpi3mr_cleanup_event_taskq(struct mpi3mr_softc *sc)
58312d1d418eSSumit Saxena {
5832b411372bSWarner Losh 	/*
5833b411372bSWarner Losh 	 * Block the taskqueue before draining. This means any new tasks won't
5834b411372bSWarner Losh 	 * be queued to a worker thread. But it doesn't stop the current workers
5835b411372bSWarner Losh 	 * that are running. taskqueue_drain waits for those correctly in the
5836b411372bSWarner Losh 	 * case of thread backed taskqueues.
5837b411372bSWarner Losh 	 */
58382d1d418eSSumit Saxena 	taskqueue_block(sc->cam_sc->ev_tq);
5839b411372bSWarner Losh 	taskqueue_drain(sc->cam_sc->ev_tq, &sc->cam_sc->ev_task);
58402d1d418eSSumit Saxena }
58412d1d418eSSumit Saxena 
58422d1d418eSSumit Saxena /**
58432d1d418eSSumit Saxena  * mpi3mr_soft_reset_handler - Reset the controller
58442d1d418eSSumit Saxena  * @sc: Adapter instance reference
58452d1d418eSSumit Saxena  * @reset_reason: Reset reason code
58462d1d418eSSumit Saxena  * @snapdump: snapdump enable/disbale bit
58472d1d418eSSumit Saxena  *
58482d1d418eSSumit Saxena  * This is an handler for recovering controller by issuing soft
58492d1d418eSSumit Saxena  * reset or diag fault reset. This is a blocking function and
58502d1d418eSSumit Saxena  * when one reset is executed if any other resets they will be
58512d1d418eSSumit Saxena  * blocked. All IOCTLs/IO will be blocked during the reset. If
58522d1d418eSSumit Saxena  * controller reset is successful then the controller will be
58532d1d418eSSumit Saxena  * reinitalized, otherwise the controller will be marked as not
58542d1d418eSSumit Saxena  * recoverable
58552d1d418eSSumit Saxena  *
58562d1d418eSSumit Saxena  * Return: 0 on success, non-zero on failure.
58572d1d418eSSumit Saxena  */
58582d1d418eSSumit Saxena int mpi3mr_soft_reset_handler(struct mpi3mr_softc *sc,
58592d1d418eSSumit Saxena 	U32 reset_reason, bool snapdump)
58602d1d418eSSumit Saxena {
58612d1d418eSSumit Saxena 	int retval = 0, i = 0;
58622d1d418eSSumit Saxena 	enum mpi3mr_iocstate ioc_state;
58632d1d418eSSumit Saxena 
58642d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "soft reset invoked: reason code: %s\n",
58652d1d418eSSumit Saxena 	    mpi3mr_reset_rc_name(reset_reason));
58662d1d418eSSumit Saxena 
58672d1d418eSSumit Saxena 	if ((reset_reason == MPI3MR_RESET_FROM_IOCTL) &&
58682d1d418eSSumit Saxena 	     (sc->reset.ioctl_reset_snapdump != true))
58692d1d418eSSumit Saxena 		snapdump = false;
58702d1d418eSSumit Saxena 
58712d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
58722d1d418eSSumit Saxena 	    "soft_reset_handler: wait if diag save is in progress\n");
58732d1d418eSSumit Saxena 	while (sc->diagsave_timeout)
58742d1d418eSSumit Saxena 		DELAY(1000 * 1000);
58752d1d418eSSumit Saxena 
58762d1d418eSSumit Saxena 	ioc_state = mpi3mr_get_iocstate(sc);
58772d1d418eSSumit Saxena 	if (ioc_state == MRIOC_STATE_UNRECOVERABLE) {
58782d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "controller is in unrecoverable state, exit\n");
58792d1d418eSSumit Saxena 		sc->reset.type = MPI3MR_NO_RESET;
58802d1d418eSSumit Saxena 		sc->reset.reason = MPI3MR_DEFAULT_RESET_REASON;
58812d1d418eSSumit Saxena 		sc->reset.status = -1;
58822d1d418eSSumit Saxena 		sc->reset.ioctl_reset_snapdump = false;
58832d1d418eSSumit Saxena 		return -1;
58842d1d418eSSumit Saxena 	}
58852d1d418eSSumit Saxena 
58862d1d418eSSumit Saxena 	if (sc->reset_in_progress) {
58872d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "reset is already in progress, exit\n");
58882d1d418eSSumit Saxena 		return -1;
58892d1d418eSSumit Saxena 	}
58902d1d418eSSumit Saxena 
58912d1d418eSSumit Saxena 	/* Pause IOs, drain and block the event taskqueue */
58922d1d418eSSumit Saxena 	xpt_freeze_simq(sc->cam_sc->sim, 1);
58932d1d418eSSumit Saxena 
58942d1d418eSSumit Saxena 	mpi3mr_cleanup_event_taskq(sc);
58952d1d418eSSumit Saxena 
58962d1d418eSSumit Saxena 	sc->reset_in_progress = 1;
58972d1d418eSSumit Saxena 	sc->block_ioctls = 1;
58982d1d418eSSumit Saxena 
58992d1d418eSSumit Saxena 	while (mpi3mr_atomic_read(&sc->pend_ioctls) && (i < PEND_IOCTLS_COMP_WAIT_TIME)) {
59002d1d418eSSumit Saxena 		ioc_state = mpi3mr_get_iocstate(sc);
59012d1d418eSSumit Saxena 		if (ioc_state == MRIOC_STATE_FAULT)
59022d1d418eSSumit Saxena 			break;
59032d1d418eSSumit Saxena 		i++;
59042d1d418eSSumit Saxena 		if (!(i % 5)) {
59052d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO,
59062d1d418eSSumit Saxena 			    "[%2ds]waiting for IOCTL to be finished from %s\n", i, __func__);
59072d1d418eSSumit Saxena 		}
59082d1d418eSSumit Saxena 		DELAY(1000 * 1000);
59092d1d418eSSumit Saxena 	}
59102d1d418eSSumit Saxena 
59112d1d418eSSumit Saxena 	if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
59122d1d418eSSumit Saxena 	    (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) &&
59132d1d418eSSumit Saxena 	    (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) {
59142d1d418eSSumit Saxena 
59152d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "Turn off events prior to reset\n");
59162d1d418eSSumit Saxena 
59172d1d418eSSumit Saxena 		for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
59182d1d418eSSumit Saxena 			sc->event_masks[i] = -1;
59192d1d418eSSumit Saxena 		mpi3mr_issue_event_notification(sc);
59202d1d418eSSumit Saxena 	}
59212d1d418eSSumit Saxena 
59222d1d418eSSumit Saxena 	mpi3mr_disable_interrupts(sc);
59232d1d418eSSumit Saxena 
59242d1d418eSSumit Saxena 	if (snapdump)
59252d1d418eSSumit Saxena 		mpi3mr_trigger_snapdump(sc, reset_reason);
59262d1d418eSSumit Saxena 
59272d1d418eSSumit Saxena 	retval = mpi3mr_issue_reset(sc,
59282d1d418eSSumit Saxena 	    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason);
59292d1d418eSSumit Saxena 	if (retval) {
59302d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to issue soft reset to the ioc\n");
59312d1d418eSSumit Saxena 		goto out;
59322d1d418eSSumit Saxena 	}
59332d1d418eSSumit Saxena 
59342d1d418eSSumit Saxena 	mpi3mr_flush_drv_cmds(sc);
59352d1d418eSSumit Saxena 	mpi3mr_flush_io(sc);
59362d1d418eSSumit Saxena 	mpi3mr_invalidate_devhandles(sc);
59372d1d418eSSumit Saxena 	mpi3mr_memset_buffers(sc);
59382d1d418eSSumit Saxena 
59392d1d418eSSumit Saxena 	if (sc->prepare_for_reset) {
59402d1d418eSSumit Saxena 		sc->prepare_for_reset = 0;
59412d1d418eSSumit Saxena 		sc->prepare_for_reset_timeout_counter = 0;
59422d1d418eSSumit Saxena 	}
59432d1d418eSSumit Saxena 
59442d1d418eSSumit Saxena 	retval = mpi3mr_initialize_ioc(sc, MPI3MR_INIT_TYPE_RESET);
59452d1d418eSSumit Saxena 	if (retval) {
59462d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "reinit after soft reset failed: reason %d\n",
59472d1d418eSSumit Saxena 		    reset_reason);
59482d1d418eSSumit Saxena 		goto out;
59492d1d418eSSumit Saxena 	}
59502d1d418eSSumit Saxena 
59512d1d418eSSumit Saxena 	DELAY((1000 * 1000) * 10);
59522d1d418eSSumit Saxena out:
59532d1d418eSSumit Saxena 	if (!retval) {
59542d1d418eSSumit Saxena 		sc->diagsave_timeout = 0;
59552d1d418eSSumit Saxena 		sc->reset_in_progress = 0;
59562d1d418eSSumit Saxena 		mpi3mr_rfresh_tgtdevs(sc);
59572d1d418eSSumit Saxena 		sc->ts_update_counter = 0;
59582d1d418eSSumit Saxena 		sc->block_ioctls = 0;
59592d1d418eSSumit Saxena 		sc->pel_abort_requested = 0;
59602d1d418eSSumit Saxena 		if (sc->pel_wait_pend) {
59612d1d418eSSumit Saxena 			sc->pel_cmds.retry_count = 0;
59622d1d418eSSumit Saxena 			mpi3mr_issue_pel_wait(sc, &sc->pel_cmds);
59632d1d418eSSumit Saxena 			mpi3mr_app_send_aen(sc);
59642d1d418eSSumit Saxena 		}
59652d1d418eSSumit Saxena 	} else {
59662d1d418eSSumit Saxena 		mpi3mr_issue_reset(sc,
59672d1d418eSSumit Saxena 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
59682d1d418eSSumit Saxena 		sc->unrecoverable = 1;
59692d1d418eSSumit Saxena 		sc->reset_in_progress = 0;
59702d1d418eSSumit Saxena 	}
59712d1d418eSSumit Saxena 
59722d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "Soft Reset: %s\n", ((retval == 0) ? "SUCCESS" : "FAILED"));
59732d1d418eSSumit Saxena 
59742d1d418eSSumit Saxena 	taskqueue_unblock(sc->cam_sc->ev_tq);
59752d1d418eSSumit Saxena 	xpt_release_simq(sc->cam_sc->sim, 1);
59762d1d418eSSumit Saxena 
59772d1d418eSSumit Saxena 	sc->reset.type = MPI3MR_NO_RESET;
59782d1d418eSSumit Saxena 	sc->reset.reason = MPI3MR_DEFAULT_RESET_REASON;
59792d1d418eSSumit Saxena 	sc->reset.status = retval;
59802d1d418eSSumit Saxena 	sc->reset.ioctl_reset_snapdump = false;
59812d1d418eSSumit Saxena 
59822d1d418eSSumit Saxena 	return retval;
59832d1d418eSSumit Saxena }
59842d1d418eSSumit Saxena 
59852d1d418eSSumit Saxena /**
59862d1d418eSSumit Saxena  * mpi3mr_issue_ioc_shutdown - shutdown controller
59872d1d418eSSumit Saxena  * @sc: Adapter instance reference
59882d1d418eSSumit Saxena  *
59892d1d418eSSumit Saxena  * Send shutodwn notification to the controller and wait for the
59902d1d418eSSumit Saxena  * shutdown_timeout for it to be completed.
59912d1d418eSSumit Saxena  *
59922d1d418eSSumit Saxena  * Return: Nothing.
59932d1d418eSSumit Saxena  */
59942d1d418eSSumit Saxena static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_softc *sc)
59952d1d418eSSumit Saxena {
59962d1d418eSSumit Saxena 	U32 ioc_config, ioc_status;
59972d1d418eSSumit Saxena 	U8 retval = 1, retry = 0;
59982d1d418eSSumit Saxena 	U32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10;
59992d1d418eSSumit Saxena 
60002d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "sending shutdown notification\n");
60012d1d418eSSumit Saxena 	if (sc->unrecoverable) {
60022d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
60032d1d418eSSumit Saxena 		    "controller is unrecoverable, shutdown not issued\n");
60042d1d418eSSumit Saxena 		return;
60052d1d418eSSumit Saxena 	}
60062d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
60072d1d418eSSumit Saxena 	if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
60082d1d418eSSumit Saxena 	    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) {
60092d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "shutdown already in progress\n");
60102d1d418eSSumit Saxena 		return;
60112d1d418eSSumit Saxena 	}
60122d1d418eSSumit Saxena 
60132d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
60142d1d418eSSumit Saxena 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
60152d1d418eSSumit Saxena 	ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
60162d1d418eSSumit Saxena 
60172d1d418eSSumit Saxena 	mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
60182d1d418eSSumit Saxena 
60192d1d418eSSumit Saxena 	if (sc->facts.shutdown_timeout)
60202d1d418eSSumit Saxena 		timeout = sc->facts.shutdown_timeout * 10;
60212d1d418eSSumit Saxena 
60222d1d418eSSumit Saxena 	do {
60232d1d418eSSumit Saxena 		ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
60242d1d418eSSumit Saxena 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
60252d1d418eSSumit Saxena 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) {
60262d1d418eSSumit Saxena 			retval = 0;
60272d1d418eSSumit Saxena 			break;
60282d1d418eSSumit Saxena 		}
60292d1d418eSSumit Saxena 
60302d1d418eSSumit Saxena 		if (sc->unrecoverable)
60312d1d418eSSumit Saxena 			break;
60322d1d418eSSumit Saxena 
60332d1d418eSSumit Saxena 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
60342d1d418eSSumit Saxena 			mpi3mr_print_fault_info(sc);
60352d1d418eSSumit Saxena 
60362d1d418eSSumit Saxena 			if (retry >= MPI3MR_MAX_SHUTDOWN_RETRY_COUNT)
60372d1d418eSSumit Saxena 				break;
60382d1d418eSSumit Saxena 
60392d1d418eSSumit Saxena 			if (mpi3mr_issue_reset(sc,
60402d1d418eSSumit Saxena 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
60412d1d418eSSumit Saxena 			    MPI3MR_RESET_FROM_CTLR_CLEANUP))
60422d1d418eSSumit Saxena 				break;
60432d1d418eSSumit Saxena 
60442d1d418eSSumit Saxena 			ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
60452d1d418eSSumit Saxena 			ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
60462d1d418eSSumit Saxena 			ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
60472d1d418eSSumit Saxena 
60482d1d418eSSumit Saxena 			mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
60492d1d418eSSumit Saxena 
60502d1d418eSSumit Saxena 			if (sc->facts.shutdown_timeout)
60512d1d418eSSumit Saxena 				timeout = sc->facts.shutdown_timeout * 10;
60522d1d418eSSumit Saxena 
60532d1d418eSSumit Saxena 			retry++;
60542d1d418eSSumit Saxena 		}
60552d1d418eSSumit Saxena 
60562d1d418eSSumit Saxena                 DELAY(100 * 1000);
60572d1d418eSSumit Saxena 
60582d1d418eSSumit Saxena 	} while (--timeout);
60592d1d418eSSumit Saxena 
60602d1d418eSSumit Saxena 	ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
60612d1d418eSSumit Saxena 	ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
60622d1d418eSSumit Saxena 
60632d1d418eSSumit Saxena 	if (retval) {
60642d1d418eSSumit Saxena 		if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
60652d1d418eSSumit Saxena 		    == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
60662d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
60672d1d418eSSumit Saxena 			    "shutdown still in progress after timeout\n");
60682d1d418eSSumit Saxena 	}
60692d1d418eSSumit Saxena 
60702d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
60712d1d418eSSumit Saxena 	    "ioc_status/ioc_config after %s shutdown is (0x%x)/(0x%x)\n",
60722d1d418eSSumit Saxena 	    (!retval)?"successful":"failed", ioc_status,
60732d1d418eSSumit Saxena 	    ioc_config);
60742d1d418eSSumit Saxena }
60752d1d418eSSumit Saxena 
60762d1d418eSSumit Saxena /**
60772d1d418eSSumit Saxena  * mpi3mr_cleanup_ioc - Cleanup controller
60782d1d418eSSumit Saxena  * @sc: Adapter instance reference
60792d1d418eSSumit Saxena 
60802d1d418eSSumit Saxena  * controller cleanup handler, Message unit reset or soft reset
60812d1d418eSSumit Saxena  * and shutdown notification is issued to the controller.
60822d1d418eSSumit Saxena  *
60832d1d418eSSumit Saxena  * Return: Nothing.
60842d1d418eSSumit Saxena  */
60852d1d418eSSumit Saxena void mpi3mr_cleanup_ioc(struct mpi3mr_softc *sc)
60862d1d418eSSumit Saxena {
60872d1d418eSSumit Saxena 	enum mpi3mr_iocstate ioc_state;
60882d1d418eSSumit Saxena 
60892d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "cleaning up the controller\n");
60902d1d418eSSumit Saxena 	mpi3mr_disable_interrupts(sc);
60912d1d418eSSumit Saxena 
60922d1d418eSSumit Saxena 	ioc_state = mpi3mr_get_iocstate(sc);
60932d1d418eSSumit Saxena 
60942d1d418eSSumit Saxena 	if ((!sc->unrecoverable) && (!sc->reset_in_progress) &&
60952d1d418eSSumit Saxena 	    (ioc_state == MRIOC_STATE_READY)) {
60962d1d418eSSumit Saxena 		if (mpi3mr_mur_ioc(sc,
60972d1d418eSSumit Saxena 		    MPI3MR_RESET_FROM_CTLR_CLEANUP))
60982d1d418eSSumit Saxena 			mpi3mr_issue_reset(sc,
60992d1d418eSSumit Saxena 			    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
61002d1d418eSSumit Saxena 			    MPI3MR_RESET_FROM_MUR_FAILURE);
61012d1d418eSSumit Saxena 		mpi3mr_issue_ioc_shutdown(sc);
61022d1d418eSSumit Saxena 	}
61032d1d418eSSumit Saxena 
61042d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "controller cleanup completed\n");
61052d1d418eSSumit Saxena }
6106