xref: /freebsd/sys/dev/mfi/mfi_tbolt.c (revision ddbffe7f)
10d9a4ef3SDoug Ambrisko  /*-
20d9a4ef3SDoug Ambrisko  * Redistribution and use in source and binary forms, with or without
30d9a4ef3SDoug Ambrisko  * modification, are permitted provided that the following conditions
40d9a4ef3SDoug Ambrisko  * are met:
50d9a4ef3SDoug Ambrisko  *
60d9a4ef3SDoug Ambrisko  *            Copyright 1994-2009 The FreeBSD Project.
70d9a4ef3SDoug Ambrisko  *            All rights reserved.
80d9a4ef3SDoug Ambrisko  *
90d9a4ef3SDoug Ambrisko  * 1. Redistributions of source code must retain the above copyright
100d9a4ef3SDoug Ambrisko  *    notice, this list of conditions and the following disclaimer.
110d9a4ef3SDoug Ambrisko  * 2. Redistributions in binary form must reproduce the above copyright
120d9a4ef3SDoug Ambrisko  *    notice, this list of conditions and the following disclaimer in the
130d9a4ef3SDoug Ambrisko  *    documentation and/or other materials provided with the distribution.
140d9a4ef3SDoug Ambrisko  *
150d9a4ef3SDoug Ambrisko  *    THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND
160d9a4ef3SDoug Ambrisko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
170d9a4ef3SDoug Ambrisko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
180d9a4ef3SDoug Ambrisko  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FREEBSD PROJECT OR
190d9a4ef3SDoug Ambrisko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
200d9a4ef3SDoug Ambrisko  * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
210d9a4ef3SDoug Ambrisko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
220d9a4ef3SDoug Ambrisko  * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY
230d9a4ef3SDoug Ambrisko  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
240d9a4ef3SDoug Ambrisko  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
250d9a4ef3SDoug Ambrisko  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
260d9a4ef3SDoug Ambrisko  *
270d9a4ef3SDoug Ambrisko  * The views and conclusions contained in the software and documentation
280d9a4ef3SDoug Ambrisko  * are those of the authors and should not be interpreted as representing
290d9a4ef3SDoug Ambrisko  * official policies,either expressed or implied, of the FreeBSD Project.
300d9a4ef3SDoug Ambrisko  */
310d9a4ef3SDoug Ambrisko 
320d9a4ef3SDoug Ambrisko 
330d9a4ef3SDoug Ambrisko #include <sys/cdefs.h>
34a6ba0fd6SDoug Ambrisko __FBSDID("$FreeBSD$");
350d9a4ef3SDoug Ambrisko 
360d9a4ef3SDoug Ambrisko #include "opt_mfi.h"
370d9a4ef3SDoug Ambrisko 
380d9a4ef3SDoug Ambrisko #include <sys/param.h>
390d9a4ef3SDoug Ambrisko #include <sys/types.h>
400d9a4ef3SDoug Ambrisko #include <sys/kernel.h>
410d9a4ef3SDoug Ambrisko #include <sys/selinfo.h>
420d9a4ef3SDoug Ambrisko #include <sys/bus.h>
430d9a4ef3SDoug Ambrisko #include <sys/conf.h>
440d9a4ef3SDoug Ambrisko #include <sys/bio.h>
450d9a4ef3SDoug Ambrisko #include <sys/ioccom.h>
460d9a4ef3SDoug Ambrisko #include <sys/eventhandler.h>
470d9a4ef3SDoug Ambrisko #include <sys/callout.h>
480d9a4ef3SDoug Ambrisko #include <sys/uio.h>
490d9a4ef3SDoug Ambrisko #include <machine/bus.h>
50a6ba0fd6SDoug Ambrisko #include <sys/sysctl.h>
510d9a4ef3SDoug Ambrisko #include <sys/systm.h>
520d9a4ef3SDoug Ambrisko #include <sys/malloc.h>
530d9a4ef3SDoug Ambrisko 
540d9a4ef3SDoug Ambrisko #include <dev/mfi/mfireg.h>
550d9a4ef3SDoug Ambrisko #include <dev/mfi/mfi_ioctl.h>
560d9a4ef3SDoug Ambrisko #include <dev/mfi/mfivar.h>
570d9a4ef3SDoug Ambrisko 
580d9a4ef3SDoug Ambrisko struct mfi_cmd_tbolt *mfi_tbolt_get_cmd(struct mfi_softc *sc);
590d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *
600d9a4ef3SDoug Ambrisko mfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index);
610d9a4ef3SDoug Ambrisko void mfi_tbolt_complete_cmd(struct mfi_softc *sc);
620d9a4ef3SDoug Ambrisko int mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
630d9a4ef3SDoug Ambrisko     struct mfi_cmd_tbolt *cmd);
640d9a4ef3SDoug Ambrisko static inline void mfi_tbolt_return_cmd(struct mfi_softc *sc,
650d9a4ef3SDoug Ambrisko     struct mfi_cmd_tbolt *cmd);
660d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *mfi_tbolt_build_mpt_cmd(struct mfi_softc
670d9a4ef3SDoug Ambrisko     *sc, struct mfi_command *cmd);
680d9a4ef3SDoug Ambrisko uint8_t
690d9a4ef3SDoug Ambrisko mfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd);
700d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *mfi_build_and_issue_cmd(struct mfi_softc
710d9a4ef3SDoug Ambrisko     *sc, struct mfi_command *mfi_cmd);
720d9a4ef3SDoug Ambrisko int mfi_tbolt_is_ldio(struct mfi_command *mfi_cmd);
730d9a4ef3SDoug Ambrisko void mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
740d9a4ef3SDoug Ambrisko     struct mfi_cmd_tbolt *cmd);
750d9a4ef3SDoug Ambrisko static int mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command
760d9a4ef3SDoug Ambrisko     *mfi_cmd, pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd);
770d9a4ef3SDoug Ambrisko static int mfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command
780d9a4ef3SDoug Ambrisko     *mfi_cmd, uint8_t *cdb);
790d9a4ef3SDoug Ambrisko void
800d9a4ef3SDoug Ambrisko map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status,
810d9a4ef3SDoug Ambrisko      uint8_t ext_status);
820d9a4ef3SDoug Ambrisko static void mfi_issue_pending_cmds_again (struct mfi_softc *sc);
830d9a4ef3SDoug Ambrisko static void mfi_kill_hba (struct mfi_softc *sc);
840d9a4ef3SDoug Ambrisko static void mfi_process_fw_state_chg_isr(void *arg);
85ddbffe7fSDoug Ambrisko static void mfi_sync_map_complete(struct mfi_command *);
86ddbffe7fSDoug Ambrisko static void mfi_queue_map_sync(struct mfi_softc *sc);
870d9a4ef3SDoug Ambrisko 
880d9a4ef3SDoug Ambrisko #define MFI_FUSION_ENABLE_INTERRUPT_MASK	(0x00000008)
890d9a4ef3SDoug Ambrisko 
900d9a4ef3SDoug Ambrisko void
910d9a4ef3SDoug Ambrisko mfi_tbolt_enable_intr_ppc(struct mfi_softc *sc)
920d9a4ef3SDoug Ambrisko {
930d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_OMSK, ~MFI_FUSION_ENABLE_INTERRUPT_MASK);
940d9a4ef3SDoug Ambrisko 	MFI_READ4(sc, MFI_OMSK);
950d9a4ef3SDoug Ambrisko }
960d9a4ef3SDoug Ambrisko 
970d9a4ef3SDoug Ambrisko void
980d9a4ef3SDoug Ambrisko mfi_tbolt_disable_intr_ppc(struct mfi_softc *sc)
990d9a4ef3SDoug Ambrisko {
1000d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_OMSK, 0xFFFFFFFF);
1010d9a4ef3SDoug Ambrisko 	MFI_READ4(sc, MFI_OMSK);
1020d9a4ef3SDoug Ambrisko }
1030d9a4ef3SDoug Ambrisko 
1040d9a4ef3SDoug Ambrisko int32_t
1050d9a4ef3SDoug Ambrisko mfi_tbolt_read_fw_status_ppc(struct mfi_softc *sc)
1060d9a4ef3SDoug Ambrisko {
1070d9a4ef3SDoug Ambrisko 	return MFI_READ4(sc, MFI_OSP0);
1080d9a4ef3SDoug Ambrisko }
1090d9a4ef3SDoug Ambrisko 
1100d9a4ef3SDoug Ambrisko int32_t
1110d9a4ef3SDoug Ambrisko mfi_tbolt_check_clear_intr_ppc(struct mfi_softc *sc)
1120d9a4ef3SDoug Ambrisko {
1130d9a4ef3SDoug Ambrisko 	int32_t status, mfi_status = 0;
1140d9a4ef3SDoug Ambrisko 
1150d9a4ef3SDoug Ambrisko 	status = MFI_READ4(sc, MFI_OSTS);
1160d9a4ef3SDoug Ambrisko 
117a6ba0fd6SDoug Ambrisko 	if (status & 1) {
1180d9a4ef3SDoug Ambrisko 		MFI_WRITE4(sc, MFI_OSTS, status);
1190d9a4ef3SDoug Ambrisko 		MFI_READ4(sc, MFI_OSTS);
1200d9a4ef3SDoug Ambrisko 		if (status & MFI_STATE_CHANGE_INTERRUPT) {
1210d9a4ef3SDoug Ambrisko 			mfi_status |= MFI_FIRMWARE_STATE_CHANGE;
1220d9a4ef3SDoug Ambrisko 		}
1230d9a4ef3SDoug Ambrisko 
1240d9a4ef3SDoug Ambrisko 		return mfi_status;
1250d9a4ef3SDoug Ambrisko 	}
1260d9a4ef3SDoug Ambrisko 	if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
1270d9a4ef3SDoug Ambrisko 		return 1;
1280d9a4ef3SDoug Ambrisko 
1290d9a4ef3SDoug Ambrisko 	MFI_READ4(sc, MFI_OSTS);
1300d9a4ef3SDoug Ambrisko 	return 0;
1310d9a4ef3SDoug Ambrisko }
1320d9a4ef3SDoug Ambrisko 
1330d9a4ef3SDoug Ambrisko 
1340d9a4ef3SDoug Ambrisko void
135a6ba0fd6SDoug Ambrisko mfi_tbolt_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add,
1360d9a4ef3SDoug Ambrisko    uint32_t frame_cnt)
1370d9a4ef3SDoug Ambrisko {
1380d9a4ef3SDoug Ambrisko 	bus_add |= (MFI_REQ_DESCRIPT_FLAGS_MFA
1390d9a4ef3SDoug Ambrisko 	    << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
140a6ba0fd6SDoug Ambrisko 	MFI_WRITE4(sc, MFI_IQPL, (uint32_t)bus_add);
141a6ba0fd6SDoug Ambrisko 	MFI_WRITE4(sc, MFI_IQPH, (uint32_t)((uint64_t)bus_add >> 32));
1420d9a4ef3SDoug Ambrisko }
1430d9a4ef3SDoug Ambrisko 
1440d9a4ef3SDoug Ambrisko /**
1450d9a4ef3SDoug Ambrisko  * mfi_tbolt_adp_reset - For controller reset
1460d9a4ef3SDoug Ambrisko  * @regs: MFI register set
1470d9a4ef3SDoug Ambrisko  */
1480d9a4ef3SDoug Ambrisko int mfi_tbolt_adp_reset(struct mfi_softc *sc)
1490d9a4ef3SDoug Ambrisko {
1500d9a4ef3SDoug Ambrisko 	int retry = 0, i = 0;
1510d9a4ef3SDoug Ambrisko 	int HostDiag;
1520d9a4ef3SDoug Ambrisko 
1530d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 0xF);
1540d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 4);
1550d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 0xB);
1560d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 2);
1570d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 7);
1580d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 0xD);
1590d9a4ef3SDoug Ambrisko 
1600d9a4ef3SDoug Ambrisko 	for (i = 0; i < 10000; i++) ;
1610d9a4ef3SDoug Ambrisko 
1620d9a4ef3SDoug Ambrisko 	HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR);
1630d9a4ef3SDoug Ambrisko 
164a6ba0fd6SDoug Ambrisko 	while (!( HostDiag & DIAG_WRITE_ENABLE)) {
1650d9a4ef3SDoug Ambrisko 		for (i = 0; i < 1000; i++);
1660d9a4ef3SDoug Ambrisko 		HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR);
1670d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%x, "
1680d9a4ef3SDoug Ambrisko 		    "hostdiag=%x\n", retry, HostDiag);
1690d9a4ef3SDoug Ambrisko 
1700d9a4ef3SDoug Ambrisko 		if (retry++ >= 100)
1710d9a4ef3SDoug Ambrisko 			return 1;
1720d9a4ef3SDoug Ambrisko 	}
1730d9a4ef3SDoug Ambrisko 
1740d9a4ef3SDoug Ambrisko 	device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: HostDiag=%x\n", HostDiag);
1750d9a4ef3SDoug Ambrisko 
1760d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_HDR, (HostDiag | DIAG_RESET_ADAPTER));
1770d9a4ef3SDoug Ambrisko 
1780d9a4ef3SDoug Ambrisko 	for (i=0; i < 10; i++) {
1790d9a4ef3SDoug Ambrisko 		for (i = 0; i < 10000; i++);
1800d9a4ef3SDoug Ambrisko 	}
1810d9a4ef3SDoug Ambrisko 
1820d9a4ef3SDoug Ambrisko 	HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR);
183a6ba0fd6SDoug Ambrisko 	while (HostDiag & DIAG_RESET_ADAPTER) {
1840d9a4ef3SDoug Ambrisko 		for (i = 0; i < 1000; i++) ;
1850d9a4ef3SDoug Ambrisko 		HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR);
1860d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%x, "
1870d9a4ef3SDoug Ambrisko 		    "hostdiag=%x\n", retry, HostDiag);
1880d9a4ef3SDoug Ambrisko 
1890d9a4ef3SDoug Ambrisko 		if (retry++ >= 1000)
1900d9a4ef3SDoug Ambrisko 			return 1;
1910d9a4ef3SDoug Ambrisko 	}
1920d9a4ef3SDoug Ambrisko 	return 0;
1930d9a4ef3SDoug Ambrisko }
1940d9a4ef3SDoug Ambrisko 
1950d9a4ef3SDoug Ambrisko /*
1960d9a4ef3SDoug Ambrisko  *******************************************************************************************
1970d9a4ef3SDoug Ambrisko  * Description:
1980d9a4ef3SDoug Ambrisko  *      This routine initialize Thunderbolt specific device information
1990d9a4ef3SDoug Ambrisko  *******************************************************************************************
2000d9a4ef3SDoug Ambrisko  */
2010d9a4ef3SDoug Ambrisko void mfi_tbolt_init_globals(struct mfi_softc *sc)
2020d9a4ef3SDoug Ambrisko {
2030d9a4ef3SDoug Ambrisko 	/* Initialize single reply size and Message size */
2040d9a4ef3SDoug Ambrisko 	sc->reply_size = MEGASAS_THUNDERBOLT_REPLY_SIZE;
2050d9a4ef3SDoug Ambrisko 	sc->raid_io_msg_size = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
2060d9a4ef3SDoug Ambrisko 
2070d9a4ef3SDoug Ambrisko 	/*
2080d9a4ef3SDoug Ambrisko 	 * Calculating how many SGEs allowed in a allocated main message
2090d9a4ef3SDoug Ambrisko 	 * (size of the Message - Raid SCSI IO message size(except SGE))
2100d9a4ef3SDoug Ambrisko 	 * / size of SGE
2110d9a4ef3SDoug Ambrisko 	 * (0x100 - (0x90 - 0x10)) / 0x10 = 8
2120d9a4ef3SDoug Ambrisko 	 */
2130d9a4ef3SDoug Ambrisko 	sc->max_SGEs_in_main_message =
2140d9a4ef3SDoug Ambrisko 	    (uint8_t)((sc->raid_io_msg_size
2150d9a4ef3SDoug Ambrisko 	    - (sizeof(struct mfi_mpi2_request_raid_scsi_io)
2160d9a4ef3SDoug Ambrisko 	    - sizeof(MPI2_SGE_IO_UNION))) / sizeof(MPI2_SGE_IO_UNION));
2170d9a4ef3SDoug Ambrisko 	/*
2180d9a4ef3SDoug Ambrisko 	 * (Command frame size allocaed in SRB ext - Raid SCSI IO message size)
2190d9a4ef3SDoug Ambrisko 	 * / size of SGL ;
2200d9a4ef3SDoug Ambrisko 	 * (1280 - 256) / 16 = 64
2210d9a4ef3SDoug Ambrisko 	 */
2220d9a4ef3SDoug Ambrisko 	sc->max_SGEs_in_chain_message = (MR_COMMAND_SIZE
2230d9a4ef3SDoug Ambrisko 	    - sc->raid_io_msg_size) / sizeof(MPI2_SGE_IO_UNION);
2240d9a4ef3SDoug Ambrisko 	/*
2250d9a4ef3SDoug Ambrisko 	 * (0x08-1) + 0x40 = 0x47 - 0x01 = 0x46  one is left for command
2260d9a4ef3SDoug Ambrisko 	 * colscing
2270d9a4ef3SDoug Ambrisko 	*/
2280d9a4ef3SDoug Ambrisko 	sc->mfi_max_sge = (sc->max_SGEs_in_main_message - 1)
2290d9a4ef3SDoug Ambrisko 	    + sc->max_SGEs_in_chain_message - 1;
2300d9a4ef3SDoug Ambrisko 	/*
2310d9a4ef3SDoug Ambrisko 	* This is the offset in number of 4 * 32bit words to the next chain
2320d9a4ef3SDoug Ambrisko 	* (0x100 - 0x10)/0x10 = 0xF(15)
2330d9a4ef3SDoug Ambrisko 	*/
2340d9a4ef3SDoug Ambrisko 	sc->chain_offset_value_for_main_message = (sc->raid_io_msg_size
2350d9a4ef3SDoug Ambrisko 	    - sizeof(MPI2_SGE_IO_UNION))/16;
2360d9a4ef3SDoug Ambrisko 	sc->chain_offset_value_for_mpt_ptmsg
2370d9a4ef3SDoug Ambrisko 	    = offsetof(struct mfi_mpi2_request_raid_scsi_io, SGL)/16;
2380d9a4ef3SDoug Ambrisko 	sc->mfi_cmd_pool_tbolt = NULL;
2390d9a4ef3SDoug Ambrisko 	sc->request_desc_pool = NULL;
2400d9a4ef3SDoug Ambrisko }
2410d9a4ef3SDoug Ambrisko 
2420d9a4ef3SDoug Ambrisko /*
2430d9a4ef3SDoug Ambrisko  ****************************************************************************
2440d9a4ef3SDoug Ambrisko  * Description:
2450d9a4ef3SDoug Ambrisko  *      This function calculates the memory requirement for Thunderbolt
2460d9a4ef3SDoug Ambrisko  *      controller
2470d9a4ef3SDoug Ambrisko  * Return Value:
2480d9a4ef3SDoug Ambrisko  *      Total required memory in bytes
2490d9a4ef3SDoug Ambrisko  ****************************************************************************
2500d9a4ef3SDoug Ambrisko  */
2510d9a4ef3SDoug Ambrisko 
2520d9a4ef3SDoug Ambrisko uint32_t mfi_tbolt_get_memory_requirement(struct mfi_softc *sc)
2530d9a4ef3SDoug Ambrisko {
2540d9a4ef3SDoug Ambrisko 	uint32_t size;
255a6ba0fd6SDoug Ambrisko 	size = MEGASAS_THUNDERBOLT_MSG_ALLIGNMENT;	/* for Alignment */
2560d9a4ef3SDoug Ambrisko 	size += sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1);
2570d9a4ef3SDoug Ambrisko 	size += sc->reply_size * sc->mfi_max_fw_cmds;
258a6ba0fd6SDoug Ambrisko 	/* this is for SGL's */
2590d9a4ef3SDoug Ambrisko 	size += MEGASAS_MAX_SZ_CHAIN_FRAME * sc->mfi_max_fw_cmds;
2600d9a4ef3SDoug Ambrisko 	return size;
2610d9a4ef3SDoug Ambrisko }
2620d9a4ef3SDoug Ambrisko 
2630d9a4ef3SDoug Ambrisko /*
2640d9a4ef3SDoug Ambrisko  ****************************************************************************
2650d9a4ef3SDoug Ambrisko  * Description:
2660d9a4ef3SDoug Ambrisko  *      This function will prepare message pools for the Thunderbolt controller
2670d9a4ef3SDoug Ambrisko  * Arguments:
2680d9a4ef3SDoug Ambrisko  *      DevExt - HBA miniport driver's adapter data storage structure
2690d9a4ef3SDoug Ambrisko  *      pMemLocation - start of the memory allocated for Thunderbolt.
2700d9a4ef3SDoug Ambrisko  * Return Value:
2710d9a4ef3SDoug Ambrisko  *      TRUE if successful
2720d9a4ef3SDoug Ambrisko  *      FALSE if failed
2730d9a4ef3SDoug Ambrisko  ****************************************************************************
2740d9a4ef3SDoug Ambrisko  */
2750d9a4ef3SDoug Ambrisko int mfi_tbolt_init_desc_pool(struct mfi_softc *sc, uint8_t* mem_location,
2760d9a4ef3SDoug Ambrisko     uint32_t tbolt_contg_length)
2770d9a4ef3SDoug Ambrisko {
2780d9a4ef3SDoug Ambrisko 	uint32_t     offset = 0;
2790d9a4ef3SDoug Ambrisko 	uint8_t      *addr = mem_location;
2800d9a4ef3SDoug Ambrisko 
2810d9a4ef3SDoug Ambrisko 	/* Request Descriptor Base physical Address */
2820d9a4ef3SDoug Ambrisko 
2830d9a4ef3SDoug Ambrisko 	/* For Request Decriptors Virtual Memory */
2840d9a4ef3SDoug Ambrisko 	/* Initialise the aligned IO Frames Virtual Memory Pointer */
2850d9a4ef3SDoug Ambrisko 	if (((uintptr_t)addr) & (0xFF)) {
2860d9a4ef3SDoug Ambrisko 		addr = &addr[sc->raid_io_msg_size];
2870d9a4ef3SDoug Ambrisko 		addr = (uint8_t *)((uintptr_t)addr & (~0xFF));
2880d9a4ef3SDoug Ambrisko 		sc->request_message_pool_align = addr;
2890d9a4ef3SDoug Ambrisko 	} else
2900d9a4ef3SDoug Ambrisko 		sc->request_message_pool_align = addr;
2910d9a4ef3SDoug Ambrisko 
2920d9a4ef3SDoug Ambrisko 	offset = sc->request_message_pool_align - sc->request_message_pool;
2930d9a4ef3SDoug Ambrisko 	sc->request_msg_busaddr = sc->mfi_tb_busaddr + offset;
2940d9a4ef3SDoug Ambrisko 
2950d9a4ef3SDoug Ambrisko 	/* DJA XXX should this be bus dma ??? */
2960d9a4ef3SDoug Ambrisko 	/* Skip request message pool */
2970d9a4ef3SDoug Ambrisko 	addr = &addr[sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1)];
2980d9a4ef3SDoug Ambrisko 	/* Reply Frame Pool is initialized */
2990d9a4ef3SDoug Ambrisko 	sc->reply_frame_pool = (struct mfi_mpi2_reply_header *) addr;
3000d9a4ef3SDoug Ambrisko 	if (((uintptr_t)addr) & (0xFF)) {
3010d9a4ef3SDoug Ambrisko 		addr = &addr[sc->reply_size];
3020d9a4ef3SDoug Ambrisko 		addr = (uint8_t *)((uintptr_t)addr & (~0xFF));
3030d9a4ef3SDoug Ambrisko 	}
3040d9a4ef3SDoug Ambrisko 	sc->reply_frame_pool_align
3050d9a4ef3SDoug Ambrisko 		    = (struct mfi_mpi2_reply_header *)addr;
3060d9a4ef3SDoug Ambrisko 
3070d9a4ef3SDoug Ambrisko 	offset = (uintptr_t)sc->reply_frame_pool_align
3080d9a4ef3SDoug Ambrisko 	    - (uintptr_t)sc->request_message_pool;
3090d9a4ef3SDoug Ambrisko 	sc->reply_frame_busaddr = sc->mfi_tb_busaddr + offset;
3100d9a4ef3SDoug Ambrisko 
3110d9a4ef3SDoug Ambrisko 	/* Skip Reply Frame Pool */
3120d9a4ef3SDoug Ambrisko 	addr += sc->reply_size * sc->mfi_max_fw_cmds;
3130d9a4ef3SDoug Ambrisko 	sc->reply_pool_limit = addr;
3140d9a4ef3SDoug Ambrisko 
3150d9a4ef3SDoug Ambrisko 	/* initializing reply address to 0xFFFFFFFF */
3160d9a4ef3SDoug Ambrisko 	memset((uint8_t *)sc->reply_frame_pool, 0xFF,
3170d9a4ef3SDoug Ambrisko 	       (sc->reply_size * sc->mfi_max_fw_cmds));
3180d9a4ef3SDoug Ambrisko 
3190d9a4ef3SDoug Ambrisko 	offset = sc->reply_size * sc->mfi_max_fw_cmds;
3200d9a4ef3SDoug Ambrisko 	sc->sg_frame_busaddr = sc->reply_frame_busaddr + offset;
3210d9a4ef3SDoug Ambrisko 	/* initialize the last_reply_idx to 0 */
3220d9a4ef3SDoug Ambrisko 	sc->last_reply_idx = 0;
3230d9a4ef3SDoug Ambrisko 	offset = (sc->sg_frame_busaddr + (MEGASAS_MAX_SZ_CHAIN_FRAME *
3240d9a4ef3SDoug Ambrisko 	    sc->mfi_max_fw_cmds)) - sc->mfi_tb_busaddr;
3250d9a4ef3SDoug Ambrisko 	if (offset > tbolt_contg_length)
3260d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Error:Initialized more than "
3270d9a4ef3SDoug Ambrisko 		    "allocated\n");
3280d9a4ef3SDoug Ambrisko 	return 0;
3290d9a4ef3SDoug Ambrisko }
3300d9a4ef3SDoug Ambrisko 
3310d9a4ef3SDoug Ambrisko /*
3320d9a4ef3SDoug Ambrisko  ****************************************************************************
3330d9a4ef3SDoug Ambrisko  * Description:
3340d9a4ef3SDoug Ambrisko  *   This routine prepare and issue INIT2 frame to the Firmware
3350d9a4ef3SDoug Ambrisko  ****************************************************************************
3360d9a4ef3SDoug Ambrisko  */
3370d9a4ef3SDoug Ambrisko 
3380d9a4ef3SDoug Ambrisko int
3390d9a4ef3SDoug Ambrisko mfi_tbolt_init_MFI_queue(struct mfi_softc *sc)
3400d9a4ef3SDoug Ambrisko {
3410d9a4ef3SDoug Ambrisko 	struct MPI2_IOC_INIT_REQUEST   *mpi2IocInit;
3420d9a4ef3SDoug Ambrisko 	struct mfi_init_frame	*mfi_init;
3430d9a4ef3SDoug Ambrisko 	uintptr_t			offset = 0;
344a6ba0fd6SDoug Ambrisko 	bus_addr_t			phyAddress;
3450d9a4ef3SDoug Ambrisko 	MFI_ADDRESS			*mfiAddressTemp;
3460d9a4ef3SDoug Ambrisko 	struct mfi_command *cm;
3470d9a4ef3SDoug Ambrisko 	int error;
3480d9a4ef3SDoug Ambrisko 
3490d9a4ef3SDoug Ambrisko 	mpi2IocInit = (struct MPI2_IOC_INIT_REQUEST *)sc->mfi_tb_ioc_init_desc;
3500d9a4ef3SDoug Ambrisko 	/* Check if initialization is already completed */
3510d9a4ef3SDoug Ambrisko 	if (sc->MFA_enabled) {
3520d9a4ef3SDoug Ambrisko 		return 1;
3530d9a4ef3SDoug Ambrisko 	}
3540d9a4ef3SDoug Ambrisko 
3550d9a4ef3SDoug Ambrisko 	mtx_lock(&sc->mfi_io_lock);
3560d9a4ef3SDoug Ambrisko 	if ((cm = mfi_dequeue_free(sc)) == NULL) {
3570d9a4ef3SDoug Ambrisko 		mtx_unlock(&sc->mfi_io_lock);
3580d9a4ef3SDoug Ambrisko 		return (EBUSY);
3590d9a4ef3SDoug Ambrisko 	}
3600d9a4ef3SDoug Ambrisko 	cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_tb_init);
3610d9a4ef3SDoug Ambrisko 	cm->cm_frame_busaddr = sc->mfi_tb_init_busaddr;
3620d9a4ef3SDoug Ambrisko 	cm->cm_dmamap = sc->mfi_tb_init_dmamap;
3630d9a4ef3SDoug Ambrisko 	cm->cm_frame->header.context = 0;
3640d9a4ef3SDoug Ambrisko 	cm->cm_sc = sc;
3650d9a4ef3SDoug Ambrisko 	cm->cm_index = 0;
3660d9a4ef3SDoug Ambrisko 
3670d9a4ef3SDoug Ambrisko 	/*
3680d9a4ef3SDoug Ambrisko 	 * Abuse the SG list area of the frame to hold the init_qinfo
3690d9a4ef3SDoug Ambrisko 	 * object;
3700d9a4ef3SDoug Ambrisko 	 */
3710d9a4ef3SDoug Ambrisko 	mfi_init = &cm->cm_frame->init;
3720d9a4ef3SDoug Ambrisko 
3730d9a4ef3SDoug Ambrisko 	bzero(mpi2IocInit, sizeof(struct MPI2_IOC_INIT_REQUEST));
3740d9a4ef3SDoug Ambrisko 	mpi2IocInit->Function  = MPI2_FUNCTION_IOC_INIT;
3750d9a4ef3SDoug Ambrisko 	mpi2IocInit->WhoInit   = MPI2_WHOINIT_HOST_DRIVER;
3760d9a4ef3SDoug Ambrisko 
3770d9a4ef3SDoug Ambrisko 	/* set MsgVersion and HeaderVersion host driver was built with */
3780d9a4ef3SDoug Ambrisko 	mpi2IocInit->MsgVersion = MPI2_VERSION;
3790d9a4ef3SDoug Ambrisko 	mpi2IocInit->HeaderVersion = MPI2_HEADER_VERSION;
3800d9a4ef3SDoug Ambrisko 	mpi2IocInit->SystemRequestFrameSize = sc->raid_io_msg_size/4;
3810d9a4ef3SDoug Ambrisko 	mpi2IocInit->ReplyDescriptorPostQueueDepth
3820d9a4ef3SDoug Ambrisko 	    = (uint16_t)sc->mfi_max_fw_cmds;
3830d9a4ef3SDoug Ambrisko 	mpi2IocInit->ReplyFreeQueueDepth = 0; /* Not supported by MR. */
3840d9a4ef3SDoug Ambrisko 
3850d9a4ef3SDoug Ambrisko 	/* Get physical address of reply frame pool */
3860d9a4ef3SDoug Ambrisko 	offset = (uintptr_t) sc->reply_frame_pool_align
3870d9a4ef3SDoug Ambrisko 	    - (uintptr_t)sc->request_message_pool;
3880d9a4ef3SDoug Ambrisko 	phyAddress = sc->mfi_tb_busaddr + offset;
3890d9a4ef3SDoug Ambrisko 	mfiAddressTemp =
3900d9a4ef3SDoug Ambrisko 	    (MFI_ADDRESS *)&mpi2IocInit->ReplyDescriptorPostQueueAddress;
391a6ba0fd6SDoug Ambrisko 	mfiAddressTemp->u.addressLow = (uint32_t)phyAddress;
392a6ba0fd6SDoug Ambrisko 	mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32);
3930d9a4ef3SDoug Ambrisko 
3940d9a4ef3SDoug Ambrisko 	/* Get physical address of request message pool */
3950d9a4ef3SDoug Ambrisko 	offset = sc->request_message_pool_align - sc->request_message_pool;
3960d9a4ef3SDoug Ambrisko 	phyAddress =  sc->mfi_tb_busaddr + offset;
3970d9a4ef3SDoug Ambrisko 	mfiAddressTemp = (MFI_ADDRESS *)&mpi2IocInit->SystemRequestFrameBaseAddress;
398a6ba0fd6SDoug Ambrisko 	mfiAddressTemp->u.addressLow = (uint32_t)phyAddress;
399a6ba0fd6SDoug Ambrisko 	mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32);
400a6ba0fd6SDoug Ambrisko 	mpi2IocInit->ReplyFreeQueueAddress =  0; /* Not supported by MR. */
4010d9a4ef3SDoug Ambrisko 	mpi2IocInit->TimeStamp = time_uptime;
4020d9a4ef3SDoug Ambrisko 
4030d9a4ef3SDoug Ambrisko 	if (sc->verbuf) {
4040d9a4ef3SDoug Ambrisko 		snprintf((char *)sc->verbuf, strlen(MEGASAS_VERSION) + 2, "%s\n",
4050d9a4ef3SDoug Ambrisko                 MEGASAS_VERSION);
406a6ba0fd6SDoug Ambrisko 		mfi_init->driver_ver_lo = (uint32_t)sc->verbuf_h_busaddr;
407a6ba0fd6SDoug Ambrisko 		mfi_init->driver_ver_hi =
408a6ba0fd6SDoug Ambrisko 		    (uint32_t)((uint64_t)sc->verbuf_h_busaddr >> 32);
4090d9a4ef3SDoug Ambrisko 	}
4100d9a4ef3SDoug Ambrisko 	/* Get the physical address of the mpi2 ioc init command */
4110d9a4ef3SDoug Ambrisko 	phyAddress =  sc->mfi_tb_ioc_init_busaddr;
412a6ba0fd6SDoug Ambrisko 	mfi_init->qinfo_new_addr_lo = (uint32_t)phyAddress;
413a6ba0fd6SDoug Ambrisko 	mfi_init->qinfo_new_addr_hi = (uint32_t)((uint64_t)phyAddress >> 32);
4140d9a4ef3SDoug Ambrisko 	mfi_init->header.flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
4150d9a4ef3SDoug Ambrisko 
4160d9a4ef3SDoug Ambrisko 	mfi_init->header.cmd = MFI_CMD_INIT;
4170d9a4ef3SDoug Ambrisko 	mfi_init->header.data_len = sizeof(struct MPI2_IOC_INIT_REQUEST);
4180d9a4ef3SDoug Ambrisko 	mfi_init->header.cmd_status = MFI_STAT_INVALID_STATUS;
4190d9a4ef3SDoug Ambrisko 
4200d9a4ef3SDoug Ambrisko 	cm->cm_data = NULL;
4210d9a4ef3SDoug Ambrisko 	cm->cm_flags |= MFI_CMD_POLLED;
4220d9a4ef3SDoug Ambrisko 	cm->cm_timestamp = time_uptime;
4230d9a4ef3SDoug Ambrisko 	if ((error = mfi_mapcmd(sc, cm)) != 0) {
4240d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "failed to send IOC init2 "
4250d9a4ef3SDoug Ambrisko 		    "command %d at %lx\n", error, (long)cm->cm_frame_busaddr);
4260d9a4ef3SDoug Ambrisko 		mfi_release_command(cm);
4270d9a4ef3SDoug Ambrisko 		mtx_unlock(&sc->mfi_io_lock);
4280d9a4ef3SDoug Ambrisko 		return (error);
4290d9a4ef3SDoug Ambrisko 	}
4300d9a4ef3SDoug Ambrisko 	mfi_release_command(cm);
4310d9a4ef3SDoug Ambrisko 	mtx_unlock(&sc->mfi_io_lock);
4320d9a4ef3SDoug Ambrisko 
4330d9a4ef3SDoug Ambrisko 	if (mfi_init->header.cmd_status == 0) {
4340d9a4ef3SDoug Ambrisko 		sc->MFA_enabled = 1;
4350d9a4ef3SDoug Ambrisko 	}
4360d9a4ef3SDoug Ambrisko 	else {
4370d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Init command Failed %x\n",
4380d9a4ef3SDoug Ambrisko 		    mfi_init->header.cmd_status);
4390d9a4ef3SDoug Ambrisko 		return 1;
4400d9a4ef3SDoug Ambrisko 	}
4410d9a4ef3SDoug Ambrisko 
4420d9a4ef3SDoug Ambrisko 	return 0;
4430d9a4ef3SDoug Ambrisko 
4440d9a4ef3SDoug Ambrisko }
4450d9a4ef3SDoug Ambrisko 
4460d9a4ef3SDoug Ambrisko int mfi_tbolt_alloc_cmd(struct mfi_softc *sc)
4470d9a4ef3SDoug Ambrisko {
4480d9a4ef3SDoug Ambrisko 	struct mfi_cmd_tbolt *cmd;
449a6ba0fd6SDoug Ambrisko 	bus_addr_t io_req_base_phys;
4500d9a4ef3SDoug Ambrisko 	uint8_t *io_req_base;
451a6ba0fd6SDoug Ambrisko 	int i = 0, j = 0, offset = 0;
4520d9a4ef3SDoug Ambrisko 
4530d9a4ef3SDoug Ambrisko 	/*
4540d9a4ef3SDoug Ambrisko 	 * sc->mfi_cmd_pool_tbolt is an array of struct mfi_cmd_tbolt pointers.
4550d9a4ef3SDoug Ambrisko 	 * Allocate the dynamic array first and then allocate individual
4560d9a4ef3SDoug Ambrisko 	 * commands.
4570d9a4ef3SDoug Ambrisko 	 */
4580d9a4ef3SDoug Ambrisko 	sc->request_desc_pool = malloc(sizeof(
4590d9a4ef3SDoug Ambrisko 	    union mfi_mpi2_request_descriptor) * sc->mfi_max_fw_cmds,
4600d9a4ef3SDoug Ambrisko 	    M_MFIBUF, M_NOWAIT|M_ZERO);
4610d9a4ef3SDoug Ambrisko 	sc->mfi_cmd_pool_tbolt = malloc(sizeof(struct mfi_cmd_tbolt*)
4620d9a4ef3SDoug Ambrisko 	    * sc->mfi_max_fw_cmds, M_MFIBUF, M_NOWAIT|M_ZERO);
4630d9a4ef3SDoug Ambrisko 
4640d9a4ef3SDoug Ambrisko 	if (!sc->mfi_cmd_pool_tbolt) {
4650d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "out of memory. Could not alloc "
4660d9a4ef3SDoug Ambrisko 		    "memory for cmd_list_fusion\n");
4670d9a4ef3SDoug Ambrisko 		return 1;
4680d9a4ef3SDoug Ambrisko 	}
4690d9a4ef3SDoug Ambrisko 
4700d9a4ef3SDoug Ambrisko 	for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
4710d9a4ef3SDoug Ambrisko 		sc->mfi_cmd_pool_tbolt[i] = malloc(sizeof(
4720d9a4ef3SDoug Ambrisko 		    struct mfi_cmd_tbolt),M_MFIBUF, M_NOWAIT|M_ZERO);
4730d9a4ef3SDoug Ambrisko 
4740d9a4ef3SDoug Ambrisko 		if (!sc->mfi_cmd_pool_tbolt[i]) {
4750d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "Could not alloc cmd list "
4760d9a4ef3SDoug Ambrisko 			    "fusion\n");
4770d9a4ef3SDoug Ambrisko 
4780d9a4ef3SDoug Ambrisko 			for (j = 0; j < i; j++)
4790d9a4ef3SDoug Ambrisko 				free(sc->mfi_cmd_pool_tbolt[j], M_MFIBUF);
4800d9a4ef3SDoug Ambrisko 
4810d9a4ef3SDoug Ambrisko 			free(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
4820d9a4ef3SDoug Ambrisko 			sc->mfi_cmd_pool_tbolt = NULL;
4830d9a4ef3SDoug Ambrisko 		}
4840d9a4ef3SDoug Ambrisko 	}
4850d9a4ef3SDoug Ambrisko 
4860d9a4ef3SDoug Ambrisko 	/*
4870d9a4ef3SDoug Ambrisko 	 * The first 256 bytes (SMID 0) is not used. Don't add to the cmd
4880d9a4ef3SDoug Ambrisko 	 *list
4890d9a4ef3SDoug Ambrisko 	 */
4900d9a4ef3SDoug Ambrisko 	io_req_base = sc->request_message_pool_align
4910d9a4ef3SDoug Ambrisko 		+ MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
4920d9a4ef3SDoug Ambrisko 	io_req_base_phys = sc->request_msg_busaddr
4930d9a4ef3SDoug Ambrisko 		+ MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
4940d9a4ef3SDoug Ambrisko 
4950d9a4ef3SDoug Ambrisko 	/*
4960d9a4ef3SDoug Ambrisko 	 * Add all the commands to command pool (instance->cmd_pool)
4970d9a4ef3SDoug Ambrisko 	 */
4980d9a4ef3SDoug Ambrisko 	/* SMID 0 is reserved. Set SMID/index from 1 */
4990d9a4ef3SDoug Ambrisko 
5000d9a4ef3SDoug Ambrisko 	for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
5010d9a4ef3SDoug Ambrisko 		cmd = sc->mfi_cmd_pool_tbolt[i];
5020d9a4ef3SDoug Ambrisko 		offset = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * i;
5030d9a4ef3SDoug Ambrisko 		cmd->index = i + 1;
5040d9a4ef3SDoug Ambrisko 		cmd->request_desc = (union mfi_mpi2_request_descriptor *)
5050d9a4ef3SDoug Ambrisko 		    (sc->request_desc_pool + i);
5060d9a4ef3SDoug Ambrisko 		cmd->io_request = (struct mfi_mpi2_request_raid_scsi_io *)
5070d9a4ef3SDoug Ambrisko 		    (io_req_base + offset);
5080d9a4ef3SDoug Ambrisko 		cmd->io_request_phys_addr = io_req_base_phys + offset;
5090d9a4ef3SDoug Ambrisko 		cmd->sg_frame = (MPI2_SGE_IO_UNION *)(sc->reply_pool_limit
5100d9a4ef3SDoug Ambrisko 		    + i * MEGASAS_MAX_SZ_CHAIN_FRAME);
5110d9a4ef3SDoug Ambrisko 		cmd->sg_frame_phys_addr = sc->sg_frame_busaddr + i
5120d9a4ef3SDoug Ambrisko 		    * MEGASAS_MAX_SZ_CHAIN_FRAME;
5130d9a4ef3SDoug Ambrisko 
5140d9a4ef3SDoug Ambrisko 		TAILQ_INSERT_TAIL(&(sc->mfi_cmd_tbolt_tqh), cmd, next);
5150d9a4ef3SDoug Ambrisko 	}
5160d9a4ef3SDoug Ambrisko 	return 0;
5170d9a4ef3SDoug Ambrisko }
5180d9a4ef3SDoug Ambrisko 
5190d9a4ef3SDoug Ambrisko int mfi_tbolt_reset(struct mfi_softc *sc)
5200d9a4ef3SDoug Ambrisko {
5210d9a4ef3SDoug Ambrisko 	uint32_t fw_state;
5220d9a4ef3SDoug Ambrisko 
5230d9a4ef3SDoug Ambrisko 	mtx_lock(&sc->mfi_io_lock);
5240d9a4ef3SDoug Ambrisko 	if (sc->hw_crit_error) {
5250d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "HW CRITICAL ERROR\n");
5260d9a4ef3SDoug Ambrisko 		mtx_unlock(&sc->mfi_io_lock);
5270d9a4ef3SDoug Ambrisko 		return 1;
5280d9a4ef3SDoug Ambrisko 	}
5290d9a4ef3SDoug Ambrisko 
5300d9a4ef3SDoug Ambrisko 	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
5310d9a4ef3SDoug Ambrisko 		fw_state = sc->mfi_read_fw_status(sc);
532a6ba0fd6SDoug Ambrisko 		if ((fw_state & MFI_FWSTATE_FAULT) == MFI_FWSTATE_FAULT) {
5330d9a4ef3SDoug Ambrisko 			if ((sc->disableOnlineCtrlReset == 0)
5340d9a4ef3SDoug Ambrisko 			    && (sc->adpreset == 0)) {
5350d9a4ef3SDoug Ambrisko 				device_printf(sc->mfi_dev, "Adapter RESET "
5360d9a4ef3SDoug Ambrisko 				    "condition is detected\n");
5370d9a4ef3SDoug Ambrisko 				sc->adpreset = 1;
5380d9a4ef3SDoug Ambrisko 				sc->issuepend_done = 0;
5390d9a4ef3SDoug Ambrisko 				sc->MFA_enabled = 0;
5400d9a4ef3SDoug Ambrisko 				sc->last_reply_idx = 0;
5410d9a4ef3SDoug Ambrisko 				mfi_process_fw_state_chg_isr((void *) sc);
5420d9a4ef3SDoug Ambrisko 			}
5430d9a4ef3SDoug Ambrisko 			mtx_unlock(&sc->mfi_io_lock);
5440d9a4ef3SDoug Ambrisko 			return 0;
5450d9a4ef3SDoug Ambrisko 		}
5460d9a4ef3SDoug Ambrisko 	}
5470d9a4ef3SDoug Ambrisko 	mtx_unlock(&sc->mfi_io_lock);
5480d9a4ef3SDoug Ambrisko 	return 1;
5490d9a4ef3SDoug Ambrisko }
5500d9a4ef3SDoug Ambrisko 
5510d9a4ef3SDoug Ambrisko /*
5520d9a4ef3SDoug Ambrisko  * mfi_intr_tbolt - isr entry point
5530d9a4ef3SDoug Ambrisko  */
5540d9a4ef3SDoug Ambrisko void mfi_intr_tbolt(void *arg)
5550d9a4ef3SDoug Ambrisko {
5560d9a4ef3SDoug Ambrisko 	struct mfi_softc *sc = (struct mfi_softc *)arg;
5570d9a4ef3SDoug Ambrisko 
558a6ba0fd6SDoug Ambrisko 	if (sc->mfi_check_clear_intr(sc) == 1) {
5590d9a4ef3SDoug Ambrisko 		return;
5600d9a4ef3SDoug Ambrisko 	}
561a6ba0fd6SDoug Ambrisko 	if (sc->mfi_detaching)
5620d9a4ef3SDoug Ambrisko 		return;
5630d9a4ef3SDoug Ambrisko 	mtx_lock(&sc->mfi_io_lock);
5640d9a4ef3SDoug Ambrisko 	mfi_tbolt_complete_cmd(sc);
5650d9a4ef3SDoug Ambrisko 	if (sc->mfi_flags & MFI_FLAGS_QFRZN)
5660d9a4ef3SDoug Ambrisko 		sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
5670d9a4ef3SDoug Ambrisko 	mfi_startio(sc);
5680d9a4ef3SDoug Ambrisko 	mtx_unlock(&sc->mfi_io_lock);
5690d9a4ef3SDoug Ambrisko 	return;
5700d9a4ef3SDoug Ambrisko }
5710d9a4ef3SDoug Ambrisko 
5720d9a4ef3SDoug Ambrisko /**
5730d9a4ef3SDoug Ambrisko  * map_cmd_status -	Maps FW cmd status to OS cmd status
5740d9a4ef3SDoug Ambrisko  * @cmd :		Pointer to cmd
5750d9a4ef3SDoug Ambrisko  * @status :		status of cmd returned by FW
5760d9a4ef3SDoug Ambrisko  * @ext_status :	ext status of cmd returned by FW
5770d9a4ef3SDoug Ambrisko  */
5780d9a4ef3SDoug Ambrisko 
5790d9a4ef3SDoug Ambrisko void
5800d9a4ef3SDoug Ambrisko map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status,
5810d9a4ef3SDoug Ambrisko     uint8_t ext_status)
5820d9a4ef3SDoug Ambrisko {
5830d9a4ef3SDoug Ambrisko 
5840d9a4ef3SDoug Ambrisko 	switch (status) {
5850d9a4ef3SDoug Ambrisko 
5860d9a4ef3SDoug Ambrisko 		case MFI_STAT_OK:
5870d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->header.cmd_status = 0;
5880d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->dcmd.header.cmd_status = 0;
5890d9a4ef3SDoug Ambrisko 			break;
5900d9a4ef3SDoug Ambrisko 
5910d9a4ef3SDoug Ambrisko 		case MFI_STAT_SCSI_IO_FAILED:
5920d9a4ef3SDoug Ambrisko 		case MFI_STAT_LD_INIT_IN_PROGRESS:
5930d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->header.cmd_status = status;
5940d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->header.scsi_status = ext_status;
5950d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
5960d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->dcmd.header.scsi_status
5970d9a4ef3SDoug Ambrisko 			    = ext_status;
5980d9a4ef3SDoug Ambrisko 			break;
5990d9a4ef3SDoug Ambrisko 
6000d9a4ef3SDoug Ambrisko 		case MFI_STAT_SCSI_DONE_WITH_ERROR:
6010d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->header.cmd_status = ext_status;
6020d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->dcmd.header.cmd_status = ext_status;
6030d9a4ef3SDoug Ambrisko 			break;
6040d9a4ef3SDoug Ambrisko 
6050d9a4ef3SDoug Ambrisko 		case MFI_STAT_LD_OFFLINE:
6060d9a4ef3SDoug Ambrisko 		case MFI_STAT_DEVICE_NOT_FOUND:
6070d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->header.cmd_status = status;
6080d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
6090d9a4ef3SDoug Ambrisko 			break;
6100d9a4ef3SDoug Ambrisko 
6110d9a4ef3SDoug Ambrisko 		default:
6120d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->header.cmd_status = status;
6130d9a4ef3SDoug Ambrisko 			mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
6140d9a4ef3SDoug Ambrisko 			break;
6150d9a4ef3SDoug Ambrisko 		}
6160d9a4ef3SDoug Ambrisko }
6170d9a4ef3SDoug Ambrisko 
618a6ba0fd6SDoug Ambrisko /**
619a6ba0fd6SDoug Ambrisko  * mfi_tbolt_return_cmd -	Return a cmd to free command pool
620a6ba0fd6SDoug Ambrisko  * @instance:		Adapter soft state
621a6ba0fd6SDoug Ambrisko  * @cmd:		Command packet to be returned to free command pool
622a6ba0fd6SDoug Ambrisko  */
623a6ba0fd6SDoug Ambrisko static inline void
624a6ba0fd6SDoug Ambrisko mfi_tbolt_return_cmd(struct mfi_softc *sc, struct mfi_cmd_tbolt *cmd)
625a6ba0fd6SDoug Ambrisko {
626a6ba0fd6SDoug Ambrisko 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
6270d9a4ef3SDoug Ambrisko 
628a6ba0fd6SDoug Ambrisko 	TAILQ_INSERT_TAIL(&sc->mfi_cmd_tbolt_tqh, cmd, next);
629a6ba0fd6SDoug Ambrisko }
6300d9a4ef3SDoug Ambrisko 
631ddbffe7fSDoug Ambrisko void
632ddbffe7fSDoug Ambrisko mfi_tbolt_complete_cmd(struct mfi_softc *sc)
6330d9a4ef3SDoug Ambrisko {
6340d9a4ef3SDoug Ambrisko 	struct mfi_mpi2_reply_header *desc, *reply_desc;
635ddbffe7fSDoug Ambrisko 	struct mfi_command *cmd_mfi, *cmd_mfi_check;	/* For MFA Cmds */
6360d9a4ef3SDoug Ambrisko 	struct mfi_cmd_tbolt *cmd_tbolt;
6370d9a4ef3SDoug Ambrisko 	uint16_t smid;
6380d9a4ef3SDoug Ambrisko 	uint8_t reply_descript_type;
6390d9a4ef3SDoug Ambrisko 	struct mfi_mpi2_request_raid_scsi_io  *scsi_io_req;
6400d9a4ef3SDoug Ambrisko 	uint32_t status, extStatus;
6410d9a4ef3SDoug Ambrisko 	uint16_t num_completed;
6420d9a4ef3SDoug Ambrisko 	union desc_value val;
6430d9a4ef3SDoug Ambrisko 
6440d9a4ef3SDoug Ambrisko 	desc = (struct mfi_mpi2_reply_header *)
6450d9a4ef3SDoug Ambrisko 		((uintptr_t)sc->reply_frame_pool_align
6460d9a4ef3SDoug Ambrisko 		+ sc->last_reply_idx * sc->reply_size);
6470d9a4ef3SDoug Ambrisko 	reply_desc = desc;
6480d9a4ef3SDoug Ambrisko 
6490d9a4ef3SDoug Ambrisko 	if (!reply_desc)
6500d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "reply desc is NULL!!\n");
6510d9a4ef3SDoug Ambrisko 
6520d9a4ef3SDoug Ambrisko 	reply_descript_type = reply_desc->ReplyFlags
6530d9a4ef3SDoug Ambrisko 	     & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
6540d9a4ef3SDoug Ambrisko 	if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
6550d9a4ef3SDoug Ambrisko 		return;
6560d9a4ef3SDoug Ambrisko 
6570d9a4ef3SDoug Ambrisko 	num_completed = 0;
6580d9a4ef3SDoug Ambrisko 	val.word = ((union mfi_mpi2_reply_descriptor *)desc)->words;
6590d9a4ef3SDoug Ambrisko 
6600d9a4ef3SDoug Ambrisko 	/* Read Reply descriptor */
6610d9a4ef3SDoug Ambrisko 	while ((val.u.low != 0xFFFFFFFF) && (val.u.high != 0xFFFFFFFF)) {
6620d9a4ef3SDoug Ambrisko 		smid = reply_desc->SMID;
6630d9a4ef3SDoug Ambrisko 		if (!smid || smid > sc->mfi_max_fw_cmds + 1) {
6640d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "smid is %x. Cannot "
6650d9a4ef3SDoug Ambrisko 			    "proceed. Returning \n", smid);
6660d9a4ef3SDoug Ambrisko 			return;
6670d9a4ef3SDoug Ambrisko 		}
6680d9a4ef3SDoug Ambrisko 
6690d9a4ef3SDoug Ambrisko 		cmd_tbolt = sc->mfi_cmd_pool_tbolt[smid - 1];
6700d9a4ef3SDoug Ambrisko 		cmd_mfi = &sc->mfi_commands[cmd_tbolt->sync_cmd_idx];
6710d9a4ef3SDoug Ambrisko 		scsi_io_req = cmd_tbolt->io_request;
6720d9a4ef3SDoug Ambrisko 
6730d9a4ef3SDoug Ambrisko 		status = cmd_mfi->cm_frame->dcmd.header.cmd_status;
6740d9a4ef3SDoug Ambrisko 		extStatus = cmd_mfi->cm_frame->dcmd.header.scsi_status;
6750d9a4ef3SDoug Ambrisko 		map_tbolt_cmd_status(cmd_mfi, status, extStatus);
676ddbffe7fSDoug Ambrisko 
677ddbffe7fSDoug Ambrisko 		/* remove command from busy queue if not polled */
678ddbffe7fSDoug Ambrisko 		TAILQ_FOREACH(cmd_mfi_check, &sc->mfi_busy, cm_link) {
679ddbffe7fSDoug Ambrisko 			if (cmd_mfi_check == cmd_mfi) {
6800d9a4ef3SDoug Ambrisko 				mfi_remove_busy(cmd_mfi);
6810d9a4ef3SDoug Ambrisko 				break;
6820d9a4ef3SDoug Ambrisko 			}
683ddbffe7fSDoug Ambrisko 		}
684ddbffe7fSDoug Ambrisko 		cmd_mfi->cm_error = 0;
685ddbffe7fSDoug Ambrisko 		mfi_complete(sc, cmd_mfi);
686ddbffe7fSDoug Ambrisko 		mfi_tbolt_return_cmd(sc, cmd_tbolt);
6870d9a4ef3SDoug Ambrisko 
6880d9a4ef3SDoug Ambrisko 		sc->last_reply_idx++;
6890d9a4ef3SDoug Ambrisko 		if (sc->last_reply_idx >= sc->mfi_max_fw_cmds) {
6900d9a4ef3SDoug Ambrisko 			MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
6910d9a4ef3SDoug Ambrisko 			sc->last_reply_idx = 0;
6920d9a4ef3SDoug Ambrisko 		}
6930d9a4ef3SDoug Ambrisko 		/*set it back to all 0xfff.*/
6940d9a4ef3SDoug Ambrisko 		((union mfi_mpi2_reply_descriptor*)desc)->words =
6950d9a4ef3SDoug Ambrisko 			~((uint64_t)0x00);
6960d9a4ef3SDoug Ambrisko 
6970d9a4ef3SDoug Ambrisko 		num_completed++;
6980d9a4ef3SDoug Ambrisko 
6990d9a4ef3SDoug Ambrisko 		/* Get the next reply descriptor */
7000d9a4ef3SDoug Ambrisko 		desc = (struct mfi_mpi2_reply_header *)
7010d9a4ef3SDoug Ambrisko 		    ((uintptr_t)sc->reply_frame_pool_align
7020d9a4ef3SDoug Ambrisko 		    + sc->last_reply_idx * sc->reply_size);
7030d9a4ef3SDoug Ambrisko 		reply_desc = desc;
7040d9a4ef3SDoug Ambrisko 		val.word = ((union mfi_mpi2_reply_descriptor*)desc)->words;
7050d9a4ef3SDoug Ambrisko 		reply_descript_type = reply_desc->ReplyFlags
7060d9a4ef3SDoug Ambrisko 		    & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
7070d9a4ef3SDoug Ambrisko 		if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
7080d9a4ef3SDoug Ambrisko 			break;
7090d9a4ef3SDoug Ambrisko 	}
7100d9a4ef3SDoug Ambrisko 
7110d9a4ef3SDoug Ambrisko 	if (!num_completed)
7120d9a4ef3SDoug Ambrisko 		return;
7130d9a4ef3SDoug Ambrisko 
7140d9a4ef3SDoug Ambrisko 	/* update replyIndex to FW */
7150d9a4ef3SDoug Ambrisko 	if (sc->last_reply_idx)
7160d9a4ef3SDoug Ambrisko 		MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
7170d9a4ef3SDoug Ambrisko 
7180d9a4ef3SDoug Ambrisko 	return;
7190d9a4ef3SDoug Ambrisko }
7200d9a4ef3SDoug Ambrisko 
7210d9a4ef3SDoug Ambrisko /**
7220d9a4ef3SDoug Ambrisko  * mfi_get_cmd -	Get a command from the free pool
7230d9a4ef3SDoug Ambrisko  * @instance:		Adapter soft state
7240d9a4ef3SDoug Ambrisko  *
7250d9a4ef3SDoug Ambrisko  * Returns a free command from the pool
7260d9a4ef3SDoug Ambrisko  */
7270d9a4ef3SDoug Ambrisko 
7280d9a4ef3SDoug Ambrisko struct mfi_cmd_tbolt *mfi_tbolt_get_cmd(struct mfi_softc
7290d9a4ef3SDoug Ambrisko 						  *sc)
7300d9a4ef3SDoug Ambrisko {
7310d9a4ef3SDoug Ambrisko 	struct mfi_cmd_tbolt *cmd = NULL;
7320d9a4ef3SDoug Ambrisko 
7330d9a4ef3SDoug Ambrisko 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
7340d9a4ef3SDoug Ambrisko 
7350d9a4ef3SDoug Ambrisko 	cmd = TAILQ_FIRST(&sc->mfi_cmd_tbolt_tqh);
7360d9a4ef3SDoug Ambrisko 	TAILQ_REMOVE(&sc->mfi_cmd_tbolt_tqh, cmd, next);
7370d9a4ef3SDoug Ambrisko 	memset((uint8_t *)cmd->sg_frame, 0, MEGASAS_MAX_SZ_CHAIN_FRAME);
7380d9a4ef3SDoug Ambrisko 	memset((uint8_t *)cmd->io_request, 0,
7390d9a4ef3SDoug Ambrisko 	    MEGASAS_THUNDERBOLT_NEW_MSG_SIZE);
7400d9a4ef3SDoug Ambrisko 	return cmd;
7410d9a4ef3SDoug Ambrisko }
7420d9a4ef3SDoug Ambrisko 
7430d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *
7440d9a4ef3SDoug Ambrisko mfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index)
7450d9a4ef3SDoug Ambrisko {
7460d9a4ef3SDoug Ambrisko 	uint8_t *p;
7470d9a4ef3SDoug Ambrisko 
7480d9a4ef3SDoug Ambrisko 	if (index >= sc->mfi_max_fw_cmds) {
7490d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Invalid SMID (0x%x)request "
7500d9a4ef3SDoug Ambrisko 		    "for descriptor\n", index);
7510d9a4ef3SDoug Ambrisko 		return NULL;
7520d9a4ef3SDoug Ambrisko 	}
7530d9a4ef3SDoug Ambrisko 	p = sc->request_desc_pool + sizeof(union mfi_mpi2_request_descriptor)
7540d9a4ef3SDoug Ambrisko 	    * index;
7550d9a4ef3SDoug Ambrisko 	memset(p, 0, sizeof(union mfi_mpi2_request_descriptor));
7560d9a4ef3SDoug Ambrisko 	return (union mfi_mpi2_request_descriptor *)p;
7570d9a4ef3SDoug Ambrisko }
7580d9a4ef3SDoug Ambrisko 
7590d9a4ef3SDoug Ambrisko 
760a6ba0fd6SDoug Ambrisko /* Used to build IOCTL cmd */
7610d9a4ef3SDoug Ambrisko uint8_t
7620d9a4ef3SDoug Ambrisko mfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd)
7630d9a4ef3SDoug Ambrisko {
7640d9a4ef3SDoug Ambrisko 	MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain;
7650d9a4ef3SDoug Ambrisko 	struct mfi_mpi2_request_raid_scsi_io *io_req;
7660d9a4ef3SDoug Ambrisko 	struct mfi_cmd_tbolt *cmd;
7670d9a4ef3SDoug Ambrisko 
7680d9a4ef3SDoug Ambrisko 	cmd = mfi_tbolt_get_cmd(sc);
7690d9a4ef3SDoug Ambrisko 	if (!cmd)
7700d9a4ef3SDoug Ambrisko 		return EBUSY;
771a6ba0fd6SDoug Ambrisko 	mfi_cmd->cm_extra_frames = cmd->index; /* Frame count used as SMID */
7720d9a4ef3SDoug Ambrisko 	cmd->sync_cmd_idx = mfi_cmd->cm_index;
7730d9a4ef3SDoug Ambrisko 	io_req = cmd->io_request;
7740d9a4ef3SDoug Ambrisko 	mpi25_ieee_chain = (MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;
7750d9a4ef3SDoug Ambrisko 
7760d9a4ef3SDoug Ambrisko 	io_req->Function = MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
7770d9a4ef3SDoug Ambrisko 	io_req->SGLOffset0 = offsetof(struct mfi_mpi2_request_raid_scsi_io,
7780d9a4ef3SDoug Ambrisko 	    SGL) / 4;
7790d9a4ef3SDoug Ambrisko 	io_req->ChainOffset = sc->chain_offset_value_for_mpt_ptmsg;
7800d9a4ef3SDoug Ambrisko 
7810d9a4ef3SDoug Ambrisko 	mpi25_ieee_chain->Address = mfi_cmd->cm_frame_busaddr;
7820d9a4ef3SDoug Ambrisko 
7830d9a4ef3SDoug Ambrisko 	/*
7840d9a4ef3SDoug Ambrisko 	  In MFI pass thru, nextChainOffset will always be zero to
7850d9a4ef3SDoug Ambrisko 	  indicate the end of the chain.
7860d9a4ef3SDoug Ambrisko 	*/
7870d9a4ef3SDoug Ambrisko 	mpi25_ieee_chain->Flags= MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT
7880d9a4ef3SDoug Ambrisko 		| MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
7890d9a4ef3SDoug Ambrisko 
7900d9a4ef3SDoug Ambrisko 	/* setting the length to the maximum length */
7910d9a4ef3SDoug Ambrisko 	mpi25_ieee_chain->Length = 1024;
7920d9a4ef3SDoug Ambrisko 
7930d9a4ef3SDoug Ambrisko 	return 0;
7940d9a4ef3SDoug Ambrisko }
7950d9a4ef3SDoug Ambrisko 
7960d9a4ef3SDoug Ambrisko void
7970d9a4ef3SDoug Ambrisko mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
7980d9a4ef3SDoug Ambrisko     struct mfi_cmd_tbolt *cmd)
7990d9a4ef3SDoug Ambrisko {
8000d9a4ef3SDoug Ambrisko 	uint32_t start_lba_lo = 0, start_lba_hi = 0, device_id;
8010d9a4ef3SDoug Ambrisko 	struct mfi_mpi2_request_raid_scsi_io	*io_request;
8020d9a4ef3SDoug Ambrisko 	struct IO_REQUEST_INFO io_info;
8030d9a4ef3SDoug Ambrisko 
8040d9a4ef3SDoug Ambrisko 	device_id = mfi_cmd->cm_frame->io.header.target_id;
8050d9a4ef3SDoug Ambrisko 	io_request = cmd->io_request;
8060d9a4ef3SDoug Ambrisko 	io_request->RaidContext.TargetID = device_id;
8070d9a4ef3SDoug Ambrisko 	io_request->RaidContext.Status = 0;
8080d9a4ef3SDoug Ambrisko 	io_request->RaidContext.exStatus =0;
8090d9a4ef3SDoug Ambrisko 
8100d9a4ef3SDoug Ambrisko 	start_lba_lo = mfi_cmd->cm_frame->io.lba_lo;
8110d9a4ef3SDoug Ambrisko 	start_lba_hi = mfi_cmd->cm_frame->io.lba_hi;
8120d9a4ef3SDoug Ambrisko 
8130d9a4ef3SDoug Ambrisko 	memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO));
8140d9a4ef3SDoug Ambrisko 	io_info.ldStartBlock = ((uint64_t)start_lba_hi << 32) | start_lba_lo;
8150d9a4ef3SDoug Ambrisko 	io_info.numBlocks = mfi_cmd->cm_frame->io.header.data_len;
8160d9a4ef3SDoug Ambrisko 	io_info.ldTgtId = device_id;
8170d9a4ef3SDoug Ambrisko 	if ((mfi_cmd->cm_frame->header.flags & MFI_FRAME_DIR_READ) ==
8180d9a4ef3SDoug Ambrisko 	    MFI_FRAME_DIR_READ)
8190d9a4ef3SDoug Ambrisko 		io_info.isRead = 1;
8200d9a4ef3SDoug Ambrisko 
8210d9a4ef3SDoug Ambrisko 		io_request->RaidContext.timeoutValue
8220d9a4ef3SDoug Ambrisko 		     = MFI_FUSION_FP_DEFAULT_TIMEOUT;
8230d9a4ef3SDoug Ambrisko 		io_request->Function = MPI2_FUNCTION_LD_IO_REQUEST;
8240d9a4ef3SDoug Ambrisko 		io_request->DevHandle = device_id;
8250d9a4ef3SDoug Ambrisko 		cmd->request_desc->header.RequestFlags
8260d9a4ef3SDoug Ambrisko 		    = (MFI_REQ_DESCRIPT_FLAGS_LD_IO
8270d9a4ef3SDoug Ambrisko 		    << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
8280d9a4ef3SDoug Ambrisko 	if ((io_request->IoFlags == 6) && (io_info.numBlocks == 0))
8290d9a4ef3SDoug Ambrisko 		io_request->RaidContext.RegLockLength = 0x100;
8300d9a4ef3SDoug Ambrisko 	io_request->DataLength = mfi_cmd->cm_frame->io.header.data_len
8310d9a4ef3SDoug Ambrisko 	    * MFI_SECTOR_LEN;
8320d9a4ef3SDoug Ambrisko }
8330d9a4ef3SDoug Ambrisko 
8340d9a4ef3SDoug Ambrisko int mfi_tbolt_is_ldio(struct mfi_command *mfi_cmd)
8350d9a4ef3SDoug Ambrisko {
8360d9a4ef3SDoug Ambrisko 	if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_READ
8370d9a4ef3SDoug Ambrisko 	    || mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
8380d9a4ef3SDoug Ambrisko 		return 1;
8390d9a4ef3SDoug Ambrisko 	else
8400d9a4ef3SDoug Ambrisko 		return 0;
8410d9a4ef3SDoug Ambrisko }
8420d9a4ef3SDoug Ambrisko 
8430d9a4ef3SDoug Ambrisko int
8440d9a4ef3SDoug Ambrisko mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd, struct mfi_cmd_tbolt *cmd)
8450d9a4ef3SDoug Ambrisko {
8460d9a4ef3SDoug Ambrisko 	uint32_t device_id;
8470d9a4ef3SDoug Ambrisko 	uint32_t sge_count;
8480d9a4ef3SDoug Ambrisko 	uint8_t cdb[32], cdb_len;
8490d9a4ef3SDoug Ambrisko 
8500d9a4ef3SDoug Ambrisko 	memset(cdb, 0, 32);
8510d9a4ef3SDoug Ambrisko 	struct mfi_mpi2_request_raid_scsi_io *io_request = cmd->io_request;
8520d9a4ef3SDoug Ambrisko 
8530d9a4ef3SDoug Ambrisko 	device_id = mfi_cmd->cm_frame->header.target_id;
8540d9a4ef3SDoug Ambrisko 
8550d9a4ef3SDoug Ambrisko 	/* Have to build CDB here for TB as BSD don't have a scsi layer */
8560d9a4ef3SDoug Ambrisko 	if ((cdb_len = mfi_tbolt_build_cdb(sc, mfi_cmd, cdb)) == 1)
8570d9a4ef3SDoug Ambrisko 		return 1;
8580d9a4ef3SDoug Ambrisko 
8590d9a4ef3SDoug Ambrisko 	/* Just the CDB length,rest of the Flags are zero */
8600d9a4ef3SDoug Ambrisko 	io_request->IoFlags = cdb_len;
8610d9a4ef3SDoug Ambrisko 	memcpy(io_request->CDB.CDB32, cdb, 32);
8620d9a4ef3SDoug Ambrisko 
8630d9a4ef3SDoug Ambrisko 	if (mfi_tbolt_is_ldio(mfi_cmd))
8640d9a4ef3SDoug Ambrisko 		mfi_tbolt_build_ldio(sc, mfi_cmd , cmd);
8650d9a4ef3SDoug Ambrisko 	else
8660d9a4ef3SDoug Ambrisko 		return 1;
8670d9a4ef3SDoug Ambrisko 
8680d9a4ef3SDoug Ambrisko 	/*
8690d9a4ef3SDoug Ambrisko 	 * Construct SGL
8700d9a4ef3SDoug Ambrisko 	 */
8710d9a4ef3SDoug Ambrisko 	sge_count = mfi_tbolt_make_sgl(sc, mfi_cmd,
8720d9a4ef3SDoug Ambrisko 	    (pMpi25IeeeSgeChain64_t) &io_request->SGL, cmd);
8730d9a4ef3SDoug Ambrisko 	if (sge_count > sc->mfi_max_sge) {
8740d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Error. sge_count (0x%x) exceeds "
8750d9a4ef3SDoug Ambrisko 		    "max (0x%x) allowed\n", sge_count, sc->mfi_max_sge);
8760d9a4ef3SDoug Ambrisko 		return 1;
8770d9a4ef3SDoug Ambrisko 	}
8780d9a4ef3SDoug Ambrisko 	io_request->RaidContext.numSGE = sge_count;
8790d9a4ef3SDoug Ambrisko 	io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
8800d9a4ef3SDoug Ambrisko 
8810d9a4ef3SDoug Ambrisko 	if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
8820d9a4ef3SDoug Ambrisko 		io_request->Control = MPI2_SCSIIO_CONTROL_WRITE;
8830d9a4ef3SDoug Ambrisko 	else
8840d9a4ef3SDoug Ambrisko 		io_request->Control = MPI2_SCSIIO_CONTROL_READ;
8850d9a4ef3SDoug Ambrisko 
8860d9a4ef3SDoug Ambrisko 	io_request->SGLOffset0 = offsetof(
8870d9a4ef3SDoug Ambrisko 	    struct mfi_mpi2_request_raid_scsi_io, SGL)/4;
8880d9a4ef3SDoug Ambrisko 
8890d9a4ef3SDoug Ambrisko 	io_request->SenseBufferLowAddress = mfi_cmd->cm_sense_busaddr;
8900d9a4ef3SDoug Ambrisko 	io_request->SenseBufferLength = MFI_SENSE_LEN;
8910d9a4ef3SDoug Ambrisko 	return 0;
8920d9a4ef3SDoug Ambrisko }
8930d9a4ef3SDoug Ambrisko 
8940d9a4ef3SDoug Ambrisko static int
8950d9a4ef3SDoug Ambrisko mfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
8960d9a4ef3SDoug Ambrisko     uint8_t *cdb)
8970d9a4ef3SDoug Ambrisko {
8980d9a4ef3SDoug Ambrisko 	uint32_t lba_lo, lba_hi, num_lba;
8990d9a4ef3SDoug Ambrisko 	uint8_t cdb_len;
9000d9a4ef3SDoug Ambrisko 
9010d9a4ef3SDoug Ambrisko 	if (mfi_cmd == NULL || cdb == NULL)
9020d9a4ef3SDoug Ambrisko 		return 1;
9030d9a4ef3SDoug Ambrisko 	num_lba = mfi_cmd->cm_frame->io.header.data_len;
9040d9a4ef3SDoug Ambrisko 	lba_lo = mfi_cmd->cm_frame->io.lba_lo;
9050d9a4ef3SDoug Ambrisko 	lba_hi = mfi_cmd->cm_frame->io.lba_hi;
9060d9a4ef3SDoug Ambrisko 
907ddbffe7fSDoug Ambrisko 	if (lba_hi == 0 && (num_lba <= 0xFF) && (lba_lo <= 0x1FFFFF)) {
9080d9a4ef3SDoug Ambrisko 		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
9090d9a4ef3SDoug Ambrisko 			/* Read 6 or Write 6 */
9100d9a4ef3SDoug Ambrisko 			cdb[0] = (uint8_t) (0x0A);
9110d9a4ef3SDoug Ambrisko 		else
9120d9a4ef3SDoug Ambrisko 			cdb[0] = (uint8_t) (0x08);
9130d9a4ef3SDoug Ambrisko 
9140d9a4ef3SDoug Ambrisko 		cdb[4] = (uint8_t) num_lba;
9150d9a4ef3SDoug Ambrisko 		cdb[3] = (uint8_t) (lba_lo & 0xFF);
9160d9a4ef3SDoug Ambrisko 		cdb[2] = (uint8_t) (lba_lo >> 8);
9170d9a4ef3SDoug Ambrisko 		cdb[1] = (uint8_t) ((lba_lo >> 16) & 0x1F);
9180d9a4ef3SDoug Ambrisko 		cdb_len = 6;
9190d9a4ef3SDoug Ambrisko 	}
920ddbffe7fSDoug Ambrisko 	else if (lba_hi == 0 && (num_lba <= 0xFFFF) && (lba_lo <= 0xFFFFFFFF)) {
9210d9a4ef3SDoug Ambrisko 		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
9220d9a4ef3SDoug Ambrisko 			/* Read 10 or Write 10 */
9230d9a4ef3SDoug Ambrisko 			cdb[0] = (uint8_t) (0x2A);
9240d9a4ef3SDoug Ambrisko 		else
9250d9a4ef3SDoug Ambrisko 			cdb[0] = (uint8_t) (0x28);
9260d9a4ef3SDoug Ambrisko 		cdb[8] = (uint8_t) (num_lba & 0xFF);
9270d9a4ef3SDoug Ambrisko 		cdb[7] = (uint8_t) (num_lba >> 8);
9280d9a4ef3SDoug Ambrisko 		cdb[5] = (uint8_t) (lba_lo & 0xFF);
9290d9a4ef3SDoug Ambrisko 		cdb[4] = (uint8_t) (lba_lo >> 8);
9300d9a4ef3SDoug Ambrisko 		cdb[3] = (uint8_t) (lba_lo >> 16);
9310d9a4ef3SDoug Ambrisko 		cdb[2] = (uint8_t) (lba_lo >> 24);
9320d9a4ef3SDoug Ambrisko 		cdb_len = 10;
9330d9a4ef3SDoug Ambrisko 	}
934a6ba0fd6SDoug Ambrisko 	else if ((num_lba > 0xFFFF) && (lba_hi == 0)) {
9350d9a4ef3SDoug Ambrisko 		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
9360d9a4ef3SDoug Ambrisko 			/* Read 12 or Write 12 */
9370d9a4ef3SDoug Ambrisko 			cdb[0] = (uint8_t) (0xAA);
9380d9a4ef3SDoug Ambrisko 		else
9390d9a4ef3SDoug Ambrisko 			cdb[0] = (uint8_t) (0xA8);
9400d9a4ef3SDoug Ambrisko 		cdb[9] = (uint8_t) (num_lba & 0xFF);
9410d9a4ef3SDoug Ambrisko 		cdb[8] = (uint8_t) (num_lba >> 8);
9420d9a4ef3SDoug Ambrisko 		cdb[7] = (uint8_t) (num_lba >> 16);
9430d9a4ef3SDoug Ambrisko 		cdb[6] = (uint8_t) (num_lba >> 24);
9440d9a4ef3SDoug Ambrisko 		cdb[5] = (uint8_t) (lba_lo & 0xFF);
9450d9a4ef3SDoug Ambrisko 		cdb[4] = (uint8_t) (lba_lo >> 8);
9460d9a4ef3SDoug Ambrisko 		cdb[3] = (uint8_t) (lba_lo >> 16);
9470d9a4ef3SDoug Ambrisko 		cdb[2] = (uint8_t) (lba_lo >> 24);
9480d9a4ef3SDoug Ambrisko 		cdb_len = 12;
949a6ba0fd6SDoug Ambrisko 	} else {
9500d9a4ef3SDoug Ambrisko 		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
9510d9a4ef3SDoug Ambrisko 			cdb[0] = (uint8_t) (0x8A);
9520d9a4ef3SDoug Ambrisko 		else
9530d9a4ef3SDoug Ambrisko 			cdb[0] = (uint8_t) (0x88);
9540d9a4ef3SDoug Ambrisko 		cdb[13] = (uint8_t) (num_lba & 0xFF);
9550d9a4ef3SDoug Ambrisko 		cdb[12] = (uint8_t) (num_lba >> 8);
9560d9a4ef3SDoug Ambrisko 		cdb[11] = (uint8_t) (num_lba >> 16);
9570d9a4ef3SDoug Ambrisko 		cdb[10] = (uint8_t) (num_lba >> 24);
9580d9a4ef3SDoug Ambrisko 		cdb[9] = (uint8_t) (lba_lo & 0xFF);
9590d9a4ef3SDoug Ambrisko 		cdb[8] = (uint8_t) (lba_lo >> 8);
9600d9a4ef3SDoug Ambrisko 		cdb[7] = (uint8_t) (lba_lo >> 16);
9610d9a4ef3SDoug Ambrisko 		cdb[6] = (uint8_t) (lba_lo >> 24);
9620d9a4ef3SDoug Ambrisko 		cdb[5] = (uint8_t) (lba_hi & 0xFF);
9630d9a4ef3SDoug Ambrisko 		cdb[4] = (uint8_t) (lba_hi >> 8);
9640d9a4ef3SDoug Ambrisko 		cdb[3] = (uint8_t) (lba_hi >> 16);
9650d9a4ef3SDoug Ambrisko 		cdb[2] = (uint8_t) (lba_hi >> 24);
9660d9a4ef3SDoug Ambrisko 		cdb_len = 16;
9670d9a4ef3SDoug Ambrisko 	}
9680d9a4ef3SDoug Ambrisko 	return cdb_len;
9690d9a4ef3SDoug Ambrisko }
9700d9a4ef3SDoug Ambrisko 
9710d9a4ef3SDoug Ambrisko static int
9720d9a4ef3SDoug Ambrisko mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
9730d9a4ef3SDoug Ambrisko 		   pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd)
9740d9a4ef3SDoug Ambrisko {
9750d9a4ef3SDoug Ambrisko 	uint8_t i, sg_processed, sg_to_process;
9760d9a4ef3SDoug Ambrisko 	uint8_t sge_count, sge_idx;
9770d9a4ef3SDoug Ambrisko 	union mfi_sgl *os_sgl;
9780d9a4ef3SDoug Ambrisko 
9790d9a4ef3SDoug Ambrisko 	/*
9800d9a4ef3SDoug Ambrisko 	 * Return 0 if there is no data transfer
9810d9a4ef3SDoug Ambrisko 	 */
9820d9a4ef3SDoug Ambrisko 	if (!mfi_cmd->cm_sg || !mfi_cmd->cm_len) {
9830d9a4ef3SDoug Ambrisko 	 	device_printf(sc->mfi_dev, "Buffer empty \n");
9840d9a4ef3SDoug Ambrisko 		return 0;
9850d9a4ef3SDoug Ambrisko 	}
9860d9a4ef3SDoug Ambrisko 	os_sgl = mfi_cmd->cm_sg;
9870d9a4ef3SDoug Ambrisko 	sge_count = mfi_cmd->cm_frame->header.sg_count;
9880d9a4ef3SDoug Ambrisko 
9890d9a4ef3SDoug Ambrisko 	if (sge_count > sc->mfi_max_sge) {
9900d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "sgl ptr %p sg_cnt %d \n",
9910d9a4ef3SDoug Ambrisko 		    os_sgl, sge_count);
9920d9a4ef3SDoug Ambrisko 		return sge_count;
9930d9a4ef3SDoug Ambrisko 	}
9940d9a4ef3SDoug Ambrisko 
9950d9a4ef3SDoug Ambrisko 	if (sge_count > sc->max_SGEs_in_main_message)
9960d9a4ef3SDoug Ambrisko 		/* One element to store the chain info */
9970d9a4ef3SDoug Ambrisko 		sge_idx = sc->max_SGEs_in_main_message - 1;
9980d9a4ef3SDoug Ambrisko 	else
9990d9a4ef3SDoug Ambrisko 		sge_idx = sge_count;
10000d9a4ef3SDoug Ambrisko 
10010d9a4ef3SDoug Ambrisko 	for (i = 0; i < sge_idx; i++) {
10020d9a4ef3SDoug Ambrisko 		/*
1003a6ba0fd6SDoug Ambrisko 		 * For 32bit BSD we are getting 32 bit SGL's from OS
1004a6ba0fd6SDoug Ambrisko 		 * but FW only take 64 bit SGL's so copying from 32 bit
1005a6ba0fd6SDoug Ambrisko 		 * SGL's to 64.
10060d9a4ef3SDoug Ambrisko 		 */
10070d9a4ef3SDoug Ambrisko 		if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
10080d9a4ef3SDoug Ambrisko 			sgl_ptr->Length = os_sgl->sg_skinny[i].len;
10090d9a4ef3SDoug Ambrisko 			sgl_ptr->Address = os_sgl->sg_skinny[i].addr;
10100d9a4ef3SDoug Ambrisko 		} else {
10110d9a4ef3SDoug Ambrisko 			sgl_ptr->Length = os_sgl->sg32[i].len;
1012a6ba0fd6SDoug Ambrisko 			sgl_ptr->Address = os_sgl->sg32[i].addr;
10130d9a4ef3SDoug Ambrisko 		}
10140d9a4ef3SDoug Ambrisko 		sgl_ptr->Flags = 0;
10150d9a4ef3SDoug Ambrisko 		sgl_ptr++;
10160d9a4ef3SDoug Ambrisko 		cmd->io_request->ChainOffset = 0;
10170d9a4ef3SDoug Ambrisko 	}
10180d9a4ef3SDoug Ambrisko 
10190d9a4ef3SDoug Ambrisko 	sg_processed = i;
10200d9a4ef3SDoug Ambrisko 
10210d9a4ef3SDoug Ambrisko 	if (sg_processed < sge_count) {
10220d9a4ef3SDoug Ambrisko 		pMpi25IeeeSgeChain64_t sg_chain;
10230d9a4ef3SDoug Ambrisko 		sg_to_process = sge_count - sg_processed;
10240d9a4ef3SDoug Ambrisko 		cmd->io_request->ChainOffset =
10250d9a4ef3SDoug Ambrisko 		    sc->chain_offset_value_for_main_message;
10260d9a4ef3SDoug Ambrisko 		sg_chain = sgl_ptr;
10270d9a4ef3SDoug Ambrisko 		/* Prepare chain element */
10280d9a4ef3SDoug Ambrisko 		sg_chain->NextChainOffset = 0;
10290d9a4ef3SDoug Ambrisko 		sg_chain->Flags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
10300d9a4ef3SDoug Ambrisko 		    MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
10310d9a4ef3SDoug Ambrisko 		sg_chain->Length =  (sizeof(MPI2_SGE_IO_UNION) *
10320d9a4ef3SDoug Ambrisko 		    (sge_count - sg_processed));
1033a6ba0fd6SDoug Ambrisko 		sg_chain->Address = cmd->sg_frame_phys_addr;
10340d9a4ef3SDoug Ambrisko 		sgl_ptr = (pMpi25IeeeSgeChain64_t)cmd->sg_frame;
10350d9a4ef3SDoug Ambrisko 		for (; i < sge_count; i++) {
10360d9a4ef3SDoug Ambrisko 			if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
10370d9a4ef3SDoug Ambrisko 				sgl_ptr->Length = os_sgl->sg_skinny[i].len;
10380d9a4ef3SDoug Ambrisko 				sgl_ptr->Address = os_sgl->sg_skinny[i].addr;
1039a6ba0fd6SDoug Ambrisko 			} else {
10400d9a4ef3SDoug Ambrisko 				sgl_ptr->Length = os_sgl->sg32[i].len;
1041a6ba0fd6SDoug Ambrisko 				sgl_ptr->Address = os_sgl->sg32[i].addr;
10420d9a4ef3SDoug Ambrisko 			}
10430d9a4ef3SDoug Ambrisko 			sgl_ptr->Flags = 0;
10440d9a4ef3SDoug Ambrisko 			sgl_ptr++;
10450d9a4ef3SDoug Ambrisko 		}
10460d9a4ef3SDoug Ambrisko 	}
10470d9a4ef3SDoug Ambrisko 	return sge_count;
10480d9a4ef3SDoug Ambrisko }
10490d9a4ef3SDoug Ambrisko 
10500d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *
10510d9a4ef3SDoug Ambrisko mfi_build_and_issue_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd)
10520d9a4ef3SDoug Ambrisko {
10530d9a4ef3SDoug Ambrisko 	struct mfi_cmd_tbolt *cmd;
10540d9a4ef3SDoug Ambrisko 	union mfi_mpi2_request_descriptor *req_desc = NULL;
10550d9a4ef3SDoug Ambrisko 	uint16_t index;
10560d9a4ef3SDoug Ambrisko 	cmd = mfi_tbolt_get_cmd(sc);
10570d9a4ef3SDoug Ambrisko 	if (!cmd)
10580d9a4ef3SDoug Ambrisko 		return NULL;
10590d9a4ef3SDoug Ambrisko 	mfi_cmd->cm_extra_frames = cmd->index;
10600d9a4ef3SDoug Ambrisko 	cmd->sync_cmd_idx = mfi_cmd->cm_index;
10610d9a4ef3SDoug Ambrisko 
10620d9a4ef3SDoug Ambrisko 	index = cmd->index;
10630d9a4ef3SDoug Ambrisko 	req_desc = mfi_tbolt_get_request_descriptor(sc, index-1);
10640d9a4ef3SDoug Ambrisko 	if (mfi_tbolt_build_io(sc, mfi_cmd, cmd))
10650d9a4ef3SDoug Ambrisko 		return NULL;
10660d9a4ef3SDoug Ambrisko 	req_desc->header.SMID = index;
10670d9a4ef3SDoug Ambrisko 	return req_desc;
10680d9a4ef3SDoug Ambrisko }
10690d9a4ef3SDoug Ambrisko 
10700d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *
10710d9a4ef3SDoug Ambrisko mfi_tbolt_build_mpt_cmd(struct mfi_softc *sc, struct mfi_command *cmd)
10720d9a4ef3SDoug Ambrisko {
10730d9a4ef3SDoug Ambrisko 	union mfi_mpi2_request_descriptor *req_desc = NULL;
10740d9a4ef3SDoug Ambrisko 	uint16_t index;
10750d9a4ef3SDoug Ambrisko 	if (mfi_build_mpt_pass_thru(sc, cmd)) {
10760d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Couldn't build MFI pass thru "
10770d9a4ef3SDoug Ambrisko 		    "cmd\n");
10780d9a4ef3SDoug Ambrisko 		return NULL;
10790d9a4ef3SDoug Ambrisko 	}
10800d9a4ef3SDoug Ambrisko 	/* For fusion the frame_count variable is used for SMID */
10810d9a4ef3SDoug Ambrisko 	index = cmd->cm_extra_frames;
10820d9a4ef3SDoug Ambrisko 
10830d9a4ef3SDoug Ambrisko 	req_desc = mfi_tbolt_get_request_descriptor(sc, index - 1);
10840d9a4ef3SDoug Ambrisko 	if (!req_desc)
10850d9a4ef3SDoug Ambrisko 		return NULL;
10860d9a4ef3SDoug Ambrisko 
10870d9a4ef3SDoug Ambrisko 	bzero(req_desc, sizeof(req_desc));
10880d9a4ef3SDoug Ambrisko 	req_desc->header.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
10890d9a4ef3SDoug Ambrisko 	    MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
10900d9a4ef3SDoug Ambrisko 	req_desc->header.SMID = index;
10910d9a4ef3SDoug Ambrisko 	return req_desc;
10920d9a4ef3SDoug Ambrisko }
10930d9a4ef3SDoug Ambrisko 
10940d9a4ef3SDoug Ambrisko int
10950d9a4ef3SDoug Ambrisko mfi_tbolt_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
10960d9a4ef3SDoug Ambrisko {
10970d9a4ef3SDoug Ambrisko 	struct mfi_frame_header *hdr;
10980d9a4ef3SDoug Ambrisko 	uint8_t *cdb;
10990d9a4ef3SDoug Ambrisko 	union mfi_mpi2_request_descriptor *req_desc = NULL;
11000d9a4ef3SDoug Ambrisko 	int tm = MFI_POLL_TIMEOUT_SECS * 1000;
11010d9a4ef3SDoug Ambrisko 
11020d9a4ef3SDoug Ambrisko 	hdr = &cm->cm_frame->header;
11030d9a4ef3SDoug Ambrisko 	cdb = cm->cm_frame->pass.cdb;
11040d9a4ef3SDoug Ambrisko 	if (sc->adpreset)
11050d9a4ef3SDoug Ambrisko 		return 1;
11060d9a4ef3SDoug Ambrisko 	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
11070d9a4ef3SDoug Ambrisko 		cm->cm_timestamp = time_uptime;
11080d9a4ef3SDoug Ambrisko 		mfi_enqueue_busy(cm);
11090d9a4ef3SDoug Ambrisko 	}
1110ddbffe7fSDoug Ambrisko 	else {	/* still get interrupts for it */
1111ddbffe7fSDoug Ambrisko 		hdr->cmd_status = MFI_STAT_INVALID_STATUS;
11120d9a4ef3SDoug Ambrisko 		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
11130d9a4ef3SDoug Ambrisko 	}
11140d9a4ef3SDoug Ambrisko 
11150d9a4ef3SDoug Ambrisko 	if (hdr->cmd == MFI_CMD_PD_SCSI_IO) {
11160d9a4ef3SDoug Ambrisko 		/* check for inquiry commands coming from CLI */
11170d9a4ef3SDoug Ambrisko 		if (cdb[0] != 0x28 || cdb[0] != 0x2A) {
11180d9a4ef3SDoug Ambrisko 			if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) ==
11190d9a4ef3SDoug Ambrisko 			    NULL) {
11200d9a4ef3SDoug Ambrisko 				device_printf(sc->mfi_dev, "Mapping from MFI "
11210d9a4ef3SDoug Ambrisko 				    "to MPT Failed \n");
11220d9a4ef3SDoug Ambrisko 				return 1;
11230d9a4ef3SDoug Ambrisko 			}
11240d9a4ef3SDoug Ambrisko 		}
11250d9a4ef3SDoug Ambrisko 		else
11260d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "DJA NA XXX SYSPDIO\n");
11270d9a4ef3SDoug Ambrisko 	}
11280d9a4ef3SDoug Ambrisko 	else if (hdr->cmd == MFI_CMD_LD_SCSI_IO ||
11290d9a4ef3SDoug Ambrisko 	    hdr->cmd == MFI_CMD_LD_READ || hdr->cmd == MFI_CMD_LD_WRITE) {
11300d9a4ef3SDoug Ambrisko 		if ((req_desc = mfi_build_and_issue_cmd(sc, cm)) == NULL) {
11310d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "LDIO Failed \n");
11320d9a4ef3SDoug Ambrisko 			return 1;
11330d9a4ef3SDoug Ambrisko 		}
11340d9a4ef3SDoug Ambrisko 	} else
11350d9a4ef3SDoug Ambrisko 		if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == NULL) {
11360d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "Mapping from MFI to MPT "
11370d9a4ef3SDoug Ambrisko 			    "Failed\n");
11380d9a4ef3SDoug Ambrisko 			return 1;
11390d9a4ef3SDoug Ambrisko 		}
11400d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_ILQP, (req_desc->words & 0xFFFFFFFF));
11410d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_IHQP, (req_desc->words >>0x20));
11420d9a4ef3SDoug Ambrisko 
11430d9a4ef3SDoug Ambrisko 	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
11440d9a4ef3SDoug Ambrisko 		return 0;
11450d9a4ef3SDoug Ambrisko 
11460d9a4ef3SDoug Ambrisko 	/* This is a polled command, so busy-wait for it to complete. */
1147ddbffe7fSDoug Ambrisko 	while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
11480d9a4ef3SDoug Ambrisko 		DELAY(1000);
11490d9a4ef3SDoug Ambrisko 		tm -= 1;
11500d9a4ef3SDoug Ambrisko 		if (tm <= 0)
11510d9a4ef3SDoug Ambrisko 		break;
11520d9a4ef3SDoug Ambrisko 	}
11530d9a4ef3SDoug Ambrisko 
1154ddbffe7fSDoug Ambrisko 	if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
11550d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Frame %p timed out "
11560d9a4ef3SDoug Ambrisko 		    "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
11570d9a4ef3SDoug Ambrisko 		return (ETIMEDOUT);
11580d9a4ef3SDoug Ambrisko 	}
11590d9a4ef3SDoug Ambrisko 	return 0;
11600d9a4ef3SDoug Ambrisko }
11610d9a4ef3SDoug Ambrisko 
11620d9a4ef3SDoug Ambrisko static void mfi_issue_pending_cmds_again (struct mfi_softc *sc)
11630d9a4ef3SDoug Ambrisko {
11640d9a4ef3SDoug Ambrisko 	struct mfi_command *cm, *tmp;
11650d9a4ef3SDoug Ambrisko 
11660d9a4ef3SDoug Ambrisko 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
11670d9a4ef3SDoug Ambrisko 	TAILQ_FOREACH_REVERSE_SAFE(cm, &sc->mfi_busy, BUSYQ, cm_link, tmp) {
11680d9a4ef3SDoug Ambrisko 
11690d9a4ef3SDoug Ambrisko 		cm->retry_for_fw_reset++;
11700d9a4ef3SDoug Ambrisko 
11710d9a4ef3SDoug Ambrisko 		/*
11720d9a4ef3SDoug Ambrisko 		 * If a command has continuously been tried multiple times
11730d9a4ef3SDoug Ambrisko 		 * and causing a FW reset condition, no further recoveries
11740d9a4ef3SDoug Ambrisko 		 * should be performed on the controller
11750d9a4ef3SDoug Ambrisko 		 */
11760d9a4ef3SDoug Ambrisko 		if (cm->retry_for_fw_reset == 3) {
11770d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "megaraid_sas: command %d "
11780d9a4ef3SDoug Ambrisko 			    "was tried multiple times during adapter reset"
11790d9a4ef3SDoug Ambrisko 			    "Shutting down the HBA\n", cm->cm_index);
11800d9a4ef3SDoug Ambrisko 			mfi_kill_hba(sc);
11810d9a4ef3SDoug Ambrisko 			sc->hw_crit_error = 1;
11820d9a4ef3SDoug Ambrisko 			return;
11830d9a4ef3SDoug Ambrisko 		}
11840d9a4ef3SDoug Ambrisko 
11850d9a4ef3SDoug Ambrisko 		if ((cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0) {
11860d9a4ef3SDoug Ambrisko 			struct mfi_cmd_tbolt *cmd;
11870d9a4ef3SDoug Ambrisko 			mfi_remove_busy(cm);
11880d9a4ef3SDoug Ambrisko 			cmd = sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames -
11890d9a4ef3SDoug Ambrisko 			    1 ];
11900d9a4ef3SDoug Ambrisko 			mfi_tbolt_return_cmd(sc, cmd);
11910d9a4ef3SDoug Ambrisko 			if ((cm->cm_flags & MFI_ON_MFIQ_MASK) == 0) {
11920d9a4ef3SDoug Ambrisko 				if (cm->cm_frame->dcmd.opcode !=
11930d9a4ef3SDoug Ambrisko 				    MFI_DCMD_CTRL_EVENT_WAIT) {
11940d9a4ef3SDoug Ambrisko 					device_printf(sc->mfi_dev,
11950d9a4ef3SDoug Ambrisko 					    "APJ ****requeue command %d \n",
11960d9a4ef3SDoug Ambrisko 					    cm->cm_index);
11970d9a4ef3SDoug Ambrisko 					mfi_requeue_ready(cm);
11980d9a4ef3SDoug Ambrisko 				}
11990d9a4ef3SDoug Ambrisko 			}
12000d9a4ef3SDoug Ambrisko 			else
12010d9a4ef3SDoug Ambrisko 				mfi_release_command(cm);
12020d9a4ef3SDoug Ambrisko 		}
12030d9a4ef3SDoug Ambrisko 	}
12040d9a4ef3SDoug Ambrisko 	mfi_startio(sc);
12050d9a4ef3SDoug Ambrisko }
12060d9a4ef3SDoug Ambrisko 
12070d9a4ef3SDoug Ambrisko static void mfi_kill_hba (struct mfi_softc *sc)
12080d9a4ef3SDoug Ambrisko {
12090d9a4ef3SDoug Ambrisko 	if (sc->mfi_flags & MFI_FLAGS_TBOLT)
12100d9a4ef3SDoug Ambrisko 		MFI_WRITE4 (sc, 0x00,MFI_STOP_ADP);
12110d9a4ef3SDoug Ambrisko 	else
12120d9a4ef3SDoug Ambrisko 		MFI_WRITE4 (sc, MFI_IDB,MFI_STOP_ADP);
12130d9a4ef3SDoug Ambrisko }
12140d9a4ef3SDoug Ambrisko 
12150d9a4ef3SDoug Ambrisko static void mfi_process_fw_state_chg_isr(void *arg)
12160d9a4ef3SDoug Ambrisko {
12170d9a4ef3SDoug Ambrisko 	struct mfi_softc *sc= (struct mfi_softc *)arg;
12180d9a4ef3SDoug Ambrisko 	struct mfi_cmd_tbolt *cmd;
12190d9a4ef3SDoug Ambrisko 	int error, status;
12200d9a4ef3SDoug Ambrisko 
12210d9a4ef3SDoug Ambrisko 	if (sc->adpreset == 1) {
12220d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "First stage of FW reset "
12230d9a4ef3SDoug Ambrisko 		     "initiated...\n");
12240d9a4ef3SDoug Ambrisko 
12250d9a4ef3SDoug Ambrisko 		sc->mfi_adp_reset(sc);
12260d9a4ef3SDoug Ambrisko 		sc->mfi_enable_intr(sc);
12270d9a4ef3SDoug Ambrisko 
12280d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "First stage of reset complete, "
12290d9a4ef3SDoug Ambrisko 		    "second stage initiated...\n");
12300d9a4ef3SDoug Ambrisko 
12310d9a4ef3SDoug Ambrisko 		sc->adpreset = 2;
12320d9a4ef3SDoug Ambrisko 
12330d9a4ef3SDoug Ambrisko 		/* waiting for about 20 second before start the second init */
12340d9a4ef3SDoug Ambrisko 		for (int wait = 0; wait < 20000; wait++)
12350d9a4ef3SDoug Ambrisko 			DELAY(1000);
12360d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Second stage of FW reset "
12370d9a4ef3SDoug Ambrisko 		     "initiated...\n");
12380d9a4ef3SDoug Ambrisko 		while ((status = MFI_READ4(sc, MFI_RSR)) & 0x04);
12390d9a4ef3SDoug Ambrisko 
12400d9a4ef3SDoug Ambrisko 		sc->mfi_disable_intr(sc);
12410d9a4ef3SDoug Ambrisko 
12420d9a4ef3SDoug Ambrisko 		/* We expect the FW state to be READY */
12430d9a4ef3SDoug Ambrisko 		if (mfi_transition_firmware(sc)) {
1244a6ba0fd6SDoug Ambrisko 			device_printf(sc->mfi_dev, "controller is not in "
1245a6ba0fd6SDoug Ambrisko 			    "ready state\n");
12460d9a4ef3SDoug Ambrisko 			mfi_kill_hba(sc);
12470d9a4ef3SDoug Ambrisko 			sc->hw_crit_error= 1;
12480d9a4ef3SDoug Ambrisko 			return ;
12490d9a4ef3SDoug Ambrisko 		}
12500d9a4ef3SDoug Ambrisko 		if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0)
12510d9a4ef3SDoug Ambrisko 				return;
12520d9a4ef3SDoug Ambrisko 
12530d9a4ef3SDoug Ambrisko 		mtx_lock(&sc->mfi_io_lock);
12540d9a4ef3SDoug Ambrisko 
12550d9a4ef3SDoug Ambrisko 		sc->mfi_enable_intr(sc);
12560d9a4ef3SDoug Ambrisko 		sc->adpreset = 0;
12570d9a4ef3SDoug Ambrisko 		free(sc->mfi_aen_cm->cm_data, M_MFIBUF);
12580d9a4ef3SDoug Ambrisko 		mfi_remove_busy(sc->mfi_aen_cm);
12590d9a4ef3SDoug Ambrisko 		cmd = sc->mfi_cmd_pool_tbolt[sc->mfi_aen_cm->cm_extra_frames
12600d9a4ef3SDoug Ambrisko 		    - 1];
12610d9a4ef3SDoug Ambrisko 		mfi_tbolt_return_cmd(sc, cmd);
12620d9a4ef3SDoug Ambrisko 		if (sc->mfi_aen_cm) {
12630d9a4ef3SDoug Ambrisko 			mfi_release_command(sc->mfi_aen_cm);
12640d9a4ef3SDoug Ambrisko 			sc->mfi_aen_cm = NULL;
12650d9a4ef3SDoug Ambrisko 		}
1266ddbffe7fSDoug Ambrisko 		if (sc->mfi_map_sync_cm) {
1267ddbffe7fSDoug Ambrisko 			mfi_release_command(sc->mfi_map_sync_cm);
1268ddbffe7fSDoug Ambrisko 			sc->mfi_map_sync_cm = NULL;
12690d9a4ef3SDoug Ambrisko 		}
12700d9a4ef3SDoug Ambrisko 		mfi_issue_pending_cmds_again(sc);
12710d9a4ef3SDoug Ambrisko 
12720d9a4ef3SDoug Ambrisko 		/*
12730d9a4ef3SDoug Ambrisko 		 * Issue pending command can result in adapter being marked
12740d9a4ef3SDoug Ambrisko 		 * dead because of too many re-tries. Check for that
12750d9a4ef3SDoug Ambrisko 		 * condition before clearing the reset condition on the FW
12760d9a4ef3SDoug Ambrisko 		 */
12770d9a4ef3SDoug Ambrisko 		if (!sc->hw_crit_error) {
12780d9a4ef3SDoug Ambrisko 			/*
12790d9a4ef3SDoug Ambrisko 			 * Initiate AEN (Asynchronous Event Notification)
12800d9a4ef3SDoug Ambrisko 			 */
12810d9a4ef3SDoug Ambrisko 			mfi_aen_setup(sc, sc->last_seq_num);
12820d9a4ef3SDoug Ambrisko 			sc->issuepend_done = 1;
12830d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "second stage of reset "
12840d9a4ef3SDoug Ambrisko 			    "complete, FW is ready now.\n");
12850d9a4ef3SDoug Ambrisko 		} else {
12860d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "second stage of reset "
12870d9a4ef3SDoug Ambrisko 			     "never completed, hba was marked offline.\n");
12880d9a4ef3SDoug Ambrisko 		}
12890d9a4ef3SDoug Ambrisko 	} else {
12900d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "mfi_process_fw_state_chg_isr "
12910d9a4ef3SDoug Ambrisko 		    "called with unhandled value:%d\n", sc->adpreset);
12920d9a4ef3SDoug Ambrisko 	}
12930d9a4ef3SDoug Ambrisko 	mtx_unlock(&sc->mfi_io_lock);
12940d9a4ef3SDoug Ambrisko }
1295ddbffe7fSDoug Ambrisko 
1296ddbffe7fSDoug Ambrisko 
1297ddbffe7fSDoug Ambrisko /*
1298ddbffe7fSDoug Ambrisko  * The ThunderBolt HW has an option for the driver to directly
1299ddbffe7fSDoug Ambrisko  * access the underlying disks and operate on the RAID.  To
1300ddbffe7fSDoug Ambrisko  * do this there needs to be a capability to keep the RAID controller
1301ddbffe7fSDoug Ambrisko  * and driver in sync.  The FreeBSD driver does not take advantage
1302ddbffe7fSDoug Ambrisko  * of this feature since it adds a lot of complexity and slows down
1303ddbffe7fSDoug Ambrisko  * performance.  Performance is gained by using the controller's
1304ddbffe7fSDoug Ambrisko  * cache etc.
1305ddbffe7fSDoug Ambrisko  *
1306ddbffe7fSDoug Ambrisko  * Even though this driver doesn't access the disks directly, an
1307ddbffe7fSDoug Ambrisko  * AEN like command is used to inform the RAID firmware to "sync"
1308ddbffe7fSDoug Ambrisko  * with all LD's via the MFI_DCMD_LD_MAP_GET_INFO command.  This
1309ddbffe7fSDoug Ambrisko  * command in write mode will return when the RAID firmware has
1310ddbffe7fSDoug Ambrisko  * detected a change to the RAID state.  Examples of this type
1311ddbffe7fSDoug Ambrisko  * of change are removing a disk.  Once the command returns then
1312ddbffe7fSDoug Ambrisko  * the driver needs to acknowledge this and "sync" all LD's again.
1313ddbffe7fSDoug Ambrisko  * This repeats until we shutdown.  Then we need to cancel this
1314ddbffe7fSDoug Ambrisko  * pending command.
1315ddbffe7fSDoug Ambrisko  *
1316ddbffe7fSDoug Ambrisko  * If this is not done right the RAID firmware will not remove a
1317ddbffe7fSDoug Ambrisko  * pulled drive and the RAID won't go degraded etc.  Effectively,
1318ddbffe7fSDoug Ambrisko  * stopping any RAID mangement to functions.
1319ddbffe7fSDoug Ambrisko  *
1320ddbffe7fSDoug Ambrisko  * Doing another LD sync, requires the use of an event since the
1321ddbffe7fSDoug Ambrisko  * driver needs to do a mfi_wait_command and can't do that in an
1322ddbffe7fSDoug Ambrisko  * interrupt thread.
1323ddbffe7fSDoug Ambrisko  *
1324ddbffe7fSDoug Ambrisko  * The driver could get the RAID state via the MFI_DCMD_LD_MAP_GET_INFO
1325ddbffe7fSDoug Ambrisko  * That requires a bunch of structure and it is simplier to just do
1326ddbffe7fSDoug Ambrisko  * the MFI_DCMD_LD_GET_LIST versus walking the RAID map.
1327ddbffe7fSDoug Ambrisko  */
1328ddbffe7fSDoug Ambrisko 
1329ddbffe7fSDoug Ambrisko void
1330ddbffe7fSDoug Ambrisko mfi_tbolt_sync_map_info(struct mfi_softc *sc)
1331ddbffe7fSDoug Ambrisko {
1332ddbffe7fSDoug Ambrisko 	int error = 0, i;
1333ddbffe7fSDoug Ambrisko 	struct mfi_command *cmd;
1334ddbffe7fSDoug Ambrisko 	struct mfi_dcmd_frame *dcmd;
1335ddbffe7fSDoug Ambrisko 	uint32_t context = 0;
1336ddbffe7fSDoug Ambrisko 	union mfi_ld_ref *ld_sync;
1337ddbffe7fSDoug Ambrisko 	size_t ld_size;
1338ddbffe7fSDoug Ambrisko 	struct mfi_frame_header *hdr;
1339ddbffe7fSDoug Ambrisko 	struct mfi_command *cm = NULL;
1340ddbffe7fSDoug Ambrisko 	struct mfi_ld_list *list = NULL;
1341ddbffe7fSDoug Ambrisko 
1342ddbffe7fSDoug Ambrisko 	if (sc->mfi_map_sync_cm != NULL || sc->cm_map_abort)
1343ddbffe7fSDoug Ambrisko 		return;
1344ddbffe7fSDoug Ambrisko 
1345ddbffe7fSDoug Ambrisko 	mtx_lock(&sc->mfi_io_lock);
1346ddbffe7fSDoug Ambrisko 	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
1347ddbffe7fSDoug Ambrisko 	    (void **)&list, sizeof(*list));
1348ddbffe7fSDoug Ambrisko 	if (error)
1349ddbffe7fSDoug Ambrisko 		goto out;
1350ddbffe7fSDoug Ambrisko 
1351ddbffe7fSDoug Ambrisko 	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAIN;
1352ddbffe7fSDoug Ambrisko 	if (mfi_wait_command(sc, cm) != 0) {
1353ddbffe7fSDoug Ambrisko 		device_printf(sc->mfi_dev, "Failed to get device listing\n");
1354ddbffe7fSDoug Ambrisko 		goto out;
1355ddbffe7fSDoug Ambrisko 	}
1356ddbffe7fSDoug Ambrisko 
1357ddbffe7fSDoug Ambrisko 	hdr = &cm->cm_frame->header;
1358ddbffe7fSDoug Ambrisko 	if (hdr->cmd_status != MFI_STAT_OK) {
1359ddbffe7fSDoug Ambrisko 		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
1360ddbffe7fSDoug Ambrisko 			      hdr->cmd_status);
1361ddbffe7fSDoug Ambrisko 		goto out;
1362ddbffe7fSDoug Ambrisko 	}
1363ddbffe7fSDoug Ambrisko 
1364ddbffe7fSDoug Ambrisko 	ld_size = sizeof(*ld_sync) * list->ld_count;
1365ddbffe7fSDoug Ambrisko 	mtx_unlock(&sc->mfi_io_lock);
1366ddbffe7fSDoug Ambrisko 	ld_sync = (union mfi_ld_ref *) malloc(ld_size, M_MFIBUF,
1367ddbffe7fSDoug Ambrisko 	     M_WAITOK | M_ZERO);
1368ddbffe7fSDoug Ambrisko 	for (i = 0; i < list->ld_count; i++) {
1369ddbffe7fSDoug Ambrisko 		ld_sync[i].ref = list->ld_list[i].ld.ref;
1370ddbffe7fSDoug Ambrisko 	}
1371ddbffe7fSDoug Ambrisko 
1372ddbffe7fSDoug Ambrisko 	mtx_lock(&sc->mfi_io_lock);
1373ddbffe7fSDoug Ambrisko 	if ((cmd = mfi_dequeue_free(sc)) == NULL)
1374ddbffe7fSDoug Ambrisko 		return;
1375ddbffe7fSDoug Ambrisko 	context = cmd->cm_frame->header.context;
1376ddbffe7fSDoug Ambrisko 	bzero(cmd->cm_frame, sizeof(union mfi_frame));
1377ddbffe7fSDoug Ambrisko 	cmd->cm_frame->header.context = context;
1378ddbffe7fSDoug Ambrisko 
1379ddbffe7fSDoug Ambrisko 	dcmd = &cmd->cm_frame->dcmd;
1380ddbffe7fSDoug Ambrisko 	bzero(dcmd->mbox, MFI_MBOX_SIZE);
1381ddbffe7fSDoug Ambrisko 	dcmd->header.cmd = MFI_CMD_DCMD;
1382ddbffe7fSDoug Ambrisko 	dcmd->header.flags = MFI_FRAME_DIR_WRITE;
1383ddbffe7fSDoug Ambrisko 	dcmd->header.timeout = 0;
1384ddbffe7fSDoug Ambrisko 	dcmd->header.data_len = ld_size;
1385ddbffe7fSDoug Ambrisko 	dcmd->header.scsi_status = 0;
1386ddbffe7fSDoug Ambrisko 	dcmd->opcode = MFI_DCMD_LD_MAP_GET_INFO;
1387ddbffe7fSDoug Ambrisko 	cmd->cm_sg = &dcmd->sgl;
1388ddbffe7fSDoug Ambrisko 	cmd->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1389ddbffe7fSDoug Ambrisko 	cmd->cm_data = ld_sync;
1390ddbffe7fSDoug Ambrisko 	cmd->cm_private = ld_sync;
1391ddbffe7fSDoug Ambrisko 
1392ddbffe7fSDoug Ambrisko 	cmd->cm_len = ld_size;
1393ddbffe7fSDoug Ambrisko 	cmd->cm_complete = mfi_sync_map_complete;
1394ddbffe7fSDoug Ambrisko 	sc->mfi_map_sync_cm = cmd;
1395ddbffe7fSDoug Ambrisko 
1396ddbffe7fSDoug Ambrisko 	cmd->cm_flags = MFI_CMD_DATAOUT;
1397ddbffe7fSDoug Ambrisko 	cmd->cm_frame->dcmd.mbox[0] = list->ld_count;
1398ddbffe7fSDoug Ambrisko 	cmd->cm_frame->dcmd.mbox[1] = MFI_DCMD_MBOX_PEND_FLAG;
1399ddbffe7fSDoug Ambrisko 
1400ddbffe7fSDoug Ambrisko 	if ((error = mfi_mapcmd(sc, cmd)) != 0) {
1401ddbffe7fSDoug Ambrisko 		device_printf(sc->mfi_dev, "failed to send map sync\n");
1402ddbffe7fSDoug Ambrisko 		return;
1403ddbffe7fSDoug Ambrisko 	}
1404ddbffe7fSDoug Ambrisko 
1405ddbffe7fSDoug Ambrisko out:
1406ddbffe7fSDoug Ambrisko 	if (list)
1407ddbffe7fSDoug Ambrisko 		free(list, M_MFIBUF);
1408ddbffe7fSDoug Ambrisko 	if (cm)
1409ddbffe7fSDoug Ambrisko 		mfi_release_command(cm);
1410ddbffe7fSDoug Ambrisko 	mtx_unlock(&sc->mfi_io_lock);
1411ddbffe7fSDoug Ambrisko 
1412ddbffe7fSDoug Ambrisko 	return;
1413ddbffe7fSDoug Ambrisko }
1414ddbffe7fSDoug Ambrisko 
1415ddbffe7fSDoug Ambrisko 
1416ddbffe7fSDoug Ambrisko static void
1417ddbffe7fSDoug Ambrisko mfi_sync_map_complete(struct mfi_command *cm)
1418ddbffe7fSDoug Ambrisko {
1419ddbffe7fSDoug Ambrisko 	struct mfi_frame_header *hdr;
1420ddbffe7fSDoug Ambrisko 	struct mfi_softc *sc;
1421ddbffe7fSDoug Ambrisko 	int aborted = 0;
1422ddbffe7fSDoug Ambrisko 
1423ddbffe7fSDoug Ambrisko 	sc = cm->cm_sc;
1424ddbffe7fSDoug Ambrisko 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1425ddbffe7fSDoug Ambrisko 
1426ddbffe7fSDoug Ambrisko 	hdr = &cm->cm_frame->header;
1427ddbffe7fSDoug Ambrisko 
1428ddbffe7fSDoug Ambrisko 	if (sc->mfi_map_sync_cm == NULL)
1429ddbffe7fSDoug Ambrisko 		return;
1430ddbffe7fSDoug Ambrisko 
1431ddbffe7fSDoug Ambrisko 	if (sc->cm_map_abort ||
1432ddbffe7fSDoug Ambrisko 	    hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1433ddbffe7fSDoug Ambrisko 		sc->cm_map_abort = 0;
1434ddbffe7fSDoug Ambrisko 		aborted = 1;
1435ddbffe7fSDoug Ambrisko 	}
1436ddbffe7fSDoug Ambrisko 
1437ddbffe7fSDoug Ambrisko 	free(cm->cm_data, M_MFIBUF);
1438ddbffe7fSDoug Ambrisko 	sc->mfi_map_sync_cm = NULL;
1439ddbffe7fSDoug Ambrisko 	wakeup(&sc->mfi_map_sync_cm);
1440ddbffe7fSDoug Ambrisko 	mfi_release_command(cm);
1441ddbffe7fSDoug Ambrisko 
1442ddbffe7fSDoug Ambrisko 	/* set it up again so the driver can catch more events */
1443ddbffe7fSDoug Ambrisko 	if (!aborted) {
1444ddbffe7fSDoug Ambrisko 		mfi_queue_map_sync(sc);
1445ddbffe7fSDoug Ambrisko 	}
1446ddbffe7fSDoug Ambrisko }
1447ddbffe7fSDoug Ambrisko 
1448ddbffe7fSDoug Ambrisko static void
1449ddbffe7fSDoug Ambrisko mfi_queue_map_sync(struct mfi_softc *sc)
1450ddbffe7fSDoug Ambrisko {
1451ddbffe7fSDoug Ambrisko 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1452ddbffe7fSDoug Ambrisko 	taskqueue_enqueue(taskqueue_swi, &sc->mfi_map_sync_task);
1453ddbffe7fSDoug Ambrisko }
1454ddbffe7fSDoug Ambrisko 
1455ddbffe7fSDoug Ambrisko void
1456ddbffe7fSDoug Ambrisko mfi_handle_map_sync(void *context, int pending)
1457ddbffe7fSDoug Ambrisko {
1458ddbffe7fSDoug Ambrisko 	struct mfi_softc *sc;
1459ddbffe7fSDoug Ambrisko 
1460ddbffe7fSDoug Ambrisko 	sc = context;
1461ddbffe7fSDoug Ambrisko 	mfi_tbolt_sync_map_info(sc);
1462ddbffe7fSDoug Ambrisko }
1463