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