xref: /freebsd/sys/dev/mfi/mfi_tbolt.c (revision 685dc743)
10d9a4ef3SDoug Ambrisko /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
40d9a4ef3SDoug Ambrisko  * Redistribution and use in source and binary forms, with or without
50d9a4ef3SDoug Ambrisko  * modification, are permitted provided that the following conditions
60d9a4ef3SDoug Ambrisko  * are met:
70d9a4ef3SDoug Ambrisko  *
80d9a4ef3SDoug Ambrisko  *            Copyright 1994-2009 The FreeBSD Project.
90d9a4ef3SDoug Ambrisko  *            All rights reserved.
100d9a4ef3SDoug Ambrisko  *
110d9a4ef3SDoug Ambrisko  * 1. Redistributions of source code must retain the above copyright
120d9a4ef3SDoug Ambrisko  *    notice, this list of conditions and the following disclaimer.
130d9a4ef3SDoug Ambrisko  * 2. Redistributions in binary form must reproduce the above copyright
140d9a4ef3SDoug Ambrisko  *    notice, this list of conditions and the following disclaimer in the
150d9a4ef3SDoug Ambrisko  *    documentation and/or other materials provided with the distribution.
160d9a4ef3SDoug Ambrisko  *
170d9a4ef3SDoug Ambrisko  *    THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND
180d9a4ef3SDoug Ambrisko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
190d9a4ef3SDoug Ambrisko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
200d9a4ef3SDoug Ambrisko  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FREEBSD PROJECT OR
210d9a4ef3SDoug Ambrisko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
220d9a4ef3SDoug Ambrisko  * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
230d9a4ef3SDoug Ambrisko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
240d9a4ef3SDoug Ambrisko  * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY
250d9a4ef3SDoug Ambrisko  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
260d9a4ef3SDoug Ambrisko  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
270d9a4ef3SDoug Ambrisko  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
280d9a4ef3SDoug Ambrisko  *
290d9a4ef3SDoug Ambrisko  * The views and conclusions contained in the software and documentation
300d9a4ef3SDoug Ambrisko  * are those of the authors and should not be interpreted as representing
310d9a4ef3SDoug Ambrisko  * official policies,either expressed or implied, of the FreeBSD Project.
320d9a4ef3SDoug Ambrisko  */
330d9a4ef3SDoug Ambrisko 
340d9a4ef3SDoug Ambrisko #include <sys/cdefs.h>
350d9a4ef3SDoug Ambrisko #include "opt_mfi.h"
360d9a4ef3SDoug Ambrisko 
370d9a4ef3SDoug Ambrisko #include <sys/param.h>
380d9a4ef3SDoug Ambrisko #include <sys/types.h>
390d9a4ef3SDoug Ambrisko #include <sys/kernel.h>
400d9a4ef3SDoug Ambrisko #include <sys/selinfo.h>
410d9a4ef3SDoug Ambrisko #include <sys/bus.h>
420d9a4ef3SDoug Ambrisko #include <sys/conf.h>
430d9a4ef3SDoug Ambrisko #include <sys/bio.h>
440d9a4ef3SDoug Ambrisko #include <sys/ioccom.h>
450d9a4ef3SDoug Ambrisko #include <sys/eventhandler.h>
460d9a4ef3SDoug Ambrisko #include <sys/callout.h>
470d9a4ef3SDoug Ambrisko #include <sys/uio.h>
480d9a4ef3SDoug Ambrisko #include <machine/bus.h>
49a6ba0fd6SDoug Ambrisko #include <sys/sysctl.h>
500d9a4ef3SDoug Ambrisko #include <sys/systm.h>
510d9a4ef3SDoug Ambrisko #include <sys/malloc.h>
520d9a4ef3SDoug Ambrisko 
530d9a4ef3SDoug Ambrisko #include <dev/mfi/mfireg.h>
540d9a4ef3SDoug Ambrisko #include <dev/mfi/mfi_ioctl.h>
550d9a4ef3SDoug Ambrisko #include <dev/mfi/mfivar.h>
560d9a4ef3SDoug Ambrisko 
5708c89430SSteven Hartland struct mfi_cmd_tbolt *mfi_tbolt_get_cmd(struct mfi_softc *sc, struct mfi_command *);
580d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *
590d9a4ef3SDoug Ambrisko mfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index);
600d9a4ef3SDoug Ambrisko void mfi_tbolt_complete_cmd(struct mfi_softc *sc);
610d9a4ef3SDoug Ambrisko int mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
620d9a4ef3SDoug Ambrisko     struct mfi_cmd_tbolt *cmd);
630d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *mfi_tbolt_build_mpt_cmd(struct mfi_softc
640d9a4ef3SDoug Ambrisko     *sc, struct mfi_command *cmd);
650d9a4ef3SDoug Ambrisko uint8_t
660d9a4ef3SDoug Ambrisko mfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd);
670d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *mfi_build_and_issue_cmd(struct mfi_softc
680d9a4ef3SDoug Ambrisko     *sc, struct mfi_command *mfi_cmd);
690d9a4ef3SDoug Ambrisko void mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
700d9a4ef3SDoug Ambrisko     struct mfi_cmd_tbolt *cmd);
710d9a4ef3SDoug Ambrisko static int mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command
720d9a4ef3SDoug Ambrisko     *mfi_cmd, pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd);
730d9a4ef3SDoug Ambrisko void
740d9a4ef3SDoug Ambrisko map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status,
750d9a4ef3SDoug Ambrisko      uint8_t ext_status);
760d9a4ef3SDoug Ambrisko static void mfi_issue_pending_cmds_again (struct mfi_softc *sc);
770d9a4ef3SDoug Ambrisko static void mfi_kill_hba (struct mfi_softc *sc);
780d9a4ef3SDoug Ambrisko static void mfi_process_fw_state_chg_isr(void *arg);
79ddbffe7fSDoug Ambrisko static void mfi_sync_map_complete(struct mfi_command *);
80ddbffe7fSDoug Ambrisko static void mfi_queue_map_sync(struct mfi_softc *sc);
810d9a4ef3SDoug Ambrisko 
820d9a4ef3SDoug Ambrisko #define MFI_FUSION_ENABLE_INTERRUPT_MASK	(0x00000008)
830d9a4ef3SDoug Ambrisko 
8408c89430SSteven Hartland extern int	mfi_polled_cmd_timeout;
8508c89430SSteven Hartland static int	mfi_fw_reset_test = 0;
8608c89430SSteven Hartland #ifdef MFI_DEBUG
8708c89430SSteven Hartland SYSCTL_INT(_hw_mfi, OID_AUTO, fw_reset_test, CTLFLAG_RWTUN, &mfi_fw_reset_test,
8808c89430SSteven Hartland            0, "Force a firmware reset condition");
8908c89430SSteven Hartland #endif
9008c89430SSteven Hartland 
910d9a4ef3SDoug Ambrisko void
mfi_tbolt_enable_intr_ppc(struct mfi_softc * sc)920d9a4ef3SDoug Ambrisko mfi_tbolt_enable_intr_ppc(struct mfi_softc *sc)
930d9a4ef3SDoug Ambrisko {
940d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_OMSK, ~MFI_FUSION_ENABLE_INTERRUPT_MASK);
950d9a4ef3SDoug Ambrisko 	MFI_READ4(sc, MFI_OMSK);
960d9a4ef3SDoug Ambrisko }
970d9a4ef3SDoug Ambrisko 
980d9a4ef3SDoug Ambrisko void
mfi_tbolt_disable_intr_ppc(struct mfi_softc * sc)990d9a4ef3SDoug Ambrisko mfi_tbolt_disable_intr_ppc(struct mfi_softc *sc)
1000d9a4ef3SDoug Ambrisko {
1010d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_OMSK, 0xFFFFFFFF);
1020d9a4ef3SDoug Ambrisko 	MFI_READ4(sc, MFI_OMSK);
1030d9a4ef3SDoug Ambrisko }
1040d9a4ef3SDoug Ambrisko 
1050d9a4ef3SDoug Ambrisko int32_t
mfi_tbolt_read_fw_status_ppc(struct mfi_softc * sc)1060d9a4ef3SDoug Ambrisko mfi_tbolt_read_fw_status_ppc(struct mfi_softc *sc)
1070d9a4ef3SDoug Ambrisko {
1080d9a4ef3SDoug Ambrisko 	return MFI_READ4(sc, MFI_OSP0);
1090d9a4ef3SDoug Ambrisko }
1100d9a4ef3SDoug Ambrisko 
1110d9a4ef3SDoug Ambrisko int32_t
mfi_tbolt_check_clear_intr_ppc(struct mfi_softc * sc)1120d9a4ef3SDoug Ambrisko mfi_tbolt_check_clear_intr_ppc(struct mfi_softc *sc)
1130d9a4ef3SDoug Ambrisko {
1140d9a4ef3SDoug Ambrisko 	int32_t status, mfi_status = 0;
1150d9a4ef3SDoug Ambrisko 
1160d9a4ef3SDoug Ambrisko 	status = MFI_READ4(sc, MFI_OSTS);
1170d9a4ef3SDoug Ambrisko 
118a6ba0fd6SDoug Ambrisko 	if (status & 1) {
1190d9a4ef3SDoug Ambrisko 		MFI_WRITE4(sc, MFI_OSTS, status);
1200d9a4ef3SDoug Ambrisko 		MFI_READ4(sc, MFI_OSTS);
1210d9a4ef3SDoug Ambrisko 		if (status & MFI_STATE_CHANGE_INTERRUPT) {
1220d9a4ef3SDoug Ambrisko 			mfi_status |= MFI_FIRMWARE_STATE_CHANGE;
1230d9a4ef3SDoug Ambrisko 		}
1240d9a4ef3SDoug Ambrisko 
1250d9a4ef3SDoug Ambrisko 		return mfi_status;
1260d9a4ef3SDoug Ambrisko 	}
1270d9a4ef3SDoug Ambrisko 	if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
1280d9a4ef3SDoug Ambrisko 		return 1;
1290d9a4ef3SDoug Ambrisko 
1300d9a4ef3SDoug Ambrisko 	MFI_READ4(sc, MFI_OSTS);
1310d9a4ef3SDoug Ambrisko 	return 0;
1320d9a4ef3SDoug Ambrisko }
1330d9a4ef3SDoug Ambrisko 
1340d9a4ef3SDoug Ambrisko void
mfi_tbolt_issue_cmd_ppc(struct mfi_softc * sc,bus_addr_t bus_add,uint32_t frame_cnt)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 
14452d5baa2SDoug Ambrisko /*
1450d9a4ef3SDoug Ambrisko  * mfi_tbolt_adp_reset - For controller reset
1460d9a4ef3SDoug Ambrisko  * @regs: MFI register set
1470d9a4ef3SDoug Ambrisko  */
14852d5baa2SDoug Ambrisko int
mfi_tbolt_adp_reset(struct mfi_softc * sc)14952d5baa2SDoug Ambrisko mfi_tbolt_adp_reset(struct mfi_softc *sc)
1500d9a4ef3SDoug Ambrisko {
1510d9a4ef3SDoug Ambrisko 	int retry = 0, i = 0;
1520d9a4ef3SDoug Ambrisko 	int HostDiag;
1530d9a4ef3SDoug Ambrisko 
1540d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 0xF);
1550d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 4);
1560d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 0xB);
1570d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 2);
1580d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 7);
1590d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_WSR, 0xD);
1600d9a4ef3SDoug Ambrisko 
1610d9a4ef3SDoug Ambrisko 	for (i = 0; i < 10000; i++) ;
1620d9a4ef3SDoug Ambrisko 
1630d9a4ef3SDoug Ambrisko 	HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR);
1640d9a4ef3SDoug Ambrisko 
165a6ba0fd6SDoug Ambrisko 	while (!( HostDiag & DIAG_WRITE_ENABLE)) {
1660d9a4ef3SDoug Ambrisko 		for (i = 0; i < 1000; i++);
1670d9a4ef3SDoug Ambrisko 		HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR);
16808c89430SSteven Hartland 		device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%d, "
16908c89430SSteven Hartland 		    "hostdiag=%#x\n", retry, HostDiag);
1700d9a4ef3SDoug Ambrisko 
1710d9a4ef3SDoug Ambrisko 		if (retry++ >= 100)
1720d9a4ef3SDoug Ambrisko 			return 1;
1730d9a4ef3SDoug Ambrisko 	}
1740d9a4ef3SDoug Ambrisko 
17508c89430SSteven Hartland 	device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: HostDiag=%#x\n", HostDiag);
1760d9a4ef3SDoug Ambrisko 
1770d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_HDR, (HostDiag | DIAG_RESET_ADAPTER));
1780d9a4ef3SDoug Ambrisko 
1790d9a4ef3SDoug Ambrisko 	for (i=0; i < 10; i++) {
1800d9a4ef3SDoug Ambrisko 		for (i = 0; i < 10000; i++);
1810d9a4ef3SDoug Ambrisko 	}
1820d9a4ef3SDoug Ambrisko 
1830d9a4ef3SDoug Ambrisko 	HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR);
184a6ba0fd6SDoug Ambrisko 	while (HostDiag & DIAG_RESET_ADAPTER) {
1850d9a4ef3SDoug Ambrisko 		for (i = 0; i < 1000; i++) ;
1860d9a4ef3SDoug Ambrisko 		HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR);
18708c89430SSteven Hartland 		device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%d, "
18808c89430SSteven Hartland 		    "hostdiag=%#x\n", retry, HostDiag);
1890d9a4ef3SDoug Ambrisko 
1900d9a4ef3SDoug Ambrisko 		if (retry++ >= 1000)
1910d9a4ef3SDoug Ambrisko 			return 1;
1920d9a4ef3SDoug Ambrisko 	}
1930d9a4ef3SDoug Ambrisko 	return 0;
1940d9a4ef3SDoug Ambrisko }
1950d9a4ef3SDoug Ambrisko 
1960d9a4ef3SDoug Ambrisko /*
1970d9a4ef3SDoug Ambrisko  * This routine initialize Thunderbolt specific device information
1980d9a4ef3SDoug Ambrisko  */
19952d5baa2SDoug Ambrisko void
mfi_tbolt_init_globals(struct mfi_softc * sc)20052d5baa2SDoug Ambrisko mfi_tbolt_init_globals(struct mfi_softc *sc)
2010d9a4ef3SDoug Ambrisko {
2020d9a4ef3SDoug Ambrisko 	/* Initialize single reply size and Message size */
2030d9a4ef3SDoug Ambrisko 	sc->reply_size = MEGASAS_THUNDERBOLT_REPLY_SIZE;
2040d9a4ef3SDoug Ambrisko 	sc->raid_io_msg_size = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
2050d9a4ef3SDoug Ambrisko 
2060d9a4ef3SDoug Ambrisko 	/*
2070d9a4ef3SDoug Ambrisko 	 * Calculating how many SGEs allowed in a allocated main message
2080d9a4ef3SDoug Ambrisko 	 * (size of the Message - Raid SCSI IO message size(except SGE))
2090d9a4ef3SDoug Ambrisko 	 * / size of SGE
2100d9a4ef3SDoug Ambrisko 	 * (0x100 - (0x90 - 0x10)) / 0x10 = 8
2110d9a4ef3SDoug Ambrisko 	 */
2120d9a4ef3SDoug Ambrisko 	sc->max_SGEs_in_main_message =
2130d9a4ef3SDoug Ambrisko 	    (uint8_t)((sc->raid_io_msg_size
2140d9a4ef3SDoug Ambrisko 	    - (sizeof(struct mfi_mpi2_request_raid_scsi_io)
2150d9a4ef3SDoug Ambrisko 	    - sizeof(MPI2_SGE_IO_UNION))) / sizeof(MPI2_SGE_IO_UNION));
2160d9a4ef3SDoug Ambrisko 	/*
2170d9a4ef3SDoug Ambrisko 	 * (Command frame size allocaed in SRB ext - Raid SCSI IO message size)
2180d9a4ef3SDoug Ambrisko 	 * / size of SGL ;
2190d9a4ef3SDoug Ambrisko 	 * (1280 - 256) / 16 = 64
2200d9a4ef3SDoug Ambrisko 	 */
2210d9a4ef3SDoug Ambrisko 	sc->max_SGEs_in_chain_message = (MR_COMMAND_SIZE
2220d9a4ef3SDoug Ambrisko 	    - sc->raid_io_msg_size) / sizeof(MPI2_SGE_IO_UNION);
2230d9a4ef3SDoug Ambrisko 	/*
2240d9a4ef3SDoug Ambrisko 	 * (0x08-1) + 0x40 = 0x47 - 0x01 = 0x46  one is left for command
2250d9a4ef3SDoug Ambrisko 	 * colscing
2260d9a4ef3SDoug Ambrisko 	*/
2270d9a4ef3SDoug Ambrisko 	sc->mfi_max_sge = (sc->max_SGEs_in_main_message - 1)
2280d9a4ef3SDoug Ambrisko 	    + sc->max_SGEs_in_chain_message - 1;
2290d9a4ef3SDoug Ambrisko 	/*
2300d9a4ef3SDoug Ambrisko 	* This is the offset in number of 4 * 32bit words to the next chain
2310d9a4ef3SDoug Ambrisko 	* (0x100 - 0x10)/0x10 = 0xF(15)
2320d9a4ef3SDoug Ambrisko 	*/
2330d9a4ef3SDoug Ambrisko 	sc->chain_offset_value_for_main_message = (sc->raid_io_msg_size
2340d9a4ef3SDoug Ambrisko 	    - sizeof(MPI2_SGE_IO_UNION))/16;
2350d9a4ef3SDoug Ambrisko 	sc->chain_offset_value_for_mpt_ptmsg
2360d9a4ef3SDoug Ambrisko 	    = offsetof(struct mfi_mpi2_request_raid_scsi_io, SGL)/16;
2370d9a4ef3SDoug Ambrisko 	sc->mfi_cmd_pool_tbolt = NULL;
2380d9a4ef3SDoug Ambrisko 	sc->request_desc_pool = NULL;
2390d9a4ef3SDoug Ambrisko }
2400d9a4ef3SDoug Ambrisko 
2410d9a4ef3SDoug Ambrisko /*
2420d9a4ef3SDoug Ambrisko  * This function calculates the memory requirement for Thunderbolt
24352d5baa2SDoug Ambrisko  * controller, returns the total required memory in bytes
2440d9a4ef3SDoug Ambrisko  */
2450d9a4ef3SDoug Ambrisko 
24652d5baa2SDoug Ambrisko uint32_t
mfi_tbolt_get_memory_requirement(struct mfi_softc * sc)24752d5baa2SDoug Ambrisko mfi_tbolt_get_memory_requirement(struct mfi_softc *sc)
2480d9a4ef3SDoug Ambrisko {
2490d9a4ef3SDoug Ambrisko 	uint32_t size;
250a6ba0fd6SDoug Ambrisko 	size = MEGASAS_THUNDERBOLT_MSG_ALLIGNMENT;	/* for Alignment */
2510d9a4ef3SDoug Ambrisko 	size += sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1);
2520d9a4ef3SDoug Ambrisko 	size += sc->reply_size * sc->mfi_max_fw_cmds;
253a6ba0fd6SDoug Ambrisko 	/* this is for SGL's */
2540d9a4ef3SDoug Ambrisko 	size += MEGASAS_MAX_SZ_CHAIN_FRAME * sc->mfi_max_fw_cmds;
2550d9a4ef3SDoug Ambrisko 	return size;
2560d9a4ef3SDoug Ambrisko }
2570d9a4ef3SDoug Ambrisko 
2580d9a4ef3SDoug Ambrisko /*
2590d9a4ef3SDoug Ambrisko  * Description:
2600d9a4ef3SDoug Ambrisko  *      This function will prepare message pools for the Thunderbolt controller
2610d9a4ef3SDoug Ambrisko  * Arguments:
2620d9a4ef3SDoug Ambrisko  *      DevExt - HBA miniport driver's adapter data storage structure
2630d9a4ef3SDoug Ambrisko  *      pMemLocation - start of the memory allocated for Thunderbolt.
2640d9a4ef3SDoug Ambrisko  * Return Value:
2650d9a4ef3SDoug Ambrisko  *      TRUE if successful
2660d9a4ef3SDoug Ambrisko  *      FALSE if failed
2670d9a4ef3SDoug Ambrisko  */
26852d5baa2SDoug Ambrisko int
mfi_tbolt_init_desc_pool(struct mfi_softc * sc,uint8_t * mem_location,uint32_t tbolt_contg_length)26952d5baa2SDoug Ambrisko mfi_tbolt_init_desc_pool(struct mfi_softc *sc, uint8_t* mem_location,
2700d9a4ef3SDoug Ambrisko     uint32_t tbolt_contg_length)
2710d9a4ef3SDoug Ambrisko {
2720d9a4ef3SDoug Ambrisko 	uint32_t     offset = 0;
2730d9a4ef3SDoug Ambrisko 	uint8_t      *addr = mem_location;
2740d9a4ef3SDoug Ambrisko 
2750d9a4ef3SDoug Ambrisko 	/* Request Descriptor Base physical Address */
2760d9a4ef3SDoug Ambrisko 
2770d9a4ef3SDoug Ambrisko 	/* For Request Decriptors Virtual Memory */
2780d9a4ef3SDoug Ambrisko 	/* Initialise the aligned IO Frames Virtual Memory Pointer */
2790d9a4ef3SDoug Ambrisko 	if (((uintptr_t)addr) & (0xFF)) {
2800d9a4ef3SDoug Ambrisko 		addr = &addr[sc->raid_io_msg_size];
2810d9a4ef3SDoug Ambrisko 		addr = (uint8_t *)((uintptr_t)addr & (~0xFF));
2820d9a4ef3SDoug Ambrisko 		sc->request_message_pool_align = addr;
2830d9a4ef3SDoug Ambrisko 	} else
2840d9a4ef3SDoug Ambrisko 		sc->request_message_pool_align = addr;
2850d9a4ef3SDoug Ambrisko 
2860d9a4ef3SDoug Ambrisko 	offset = sc->request_message_pool_align - sc->request_message_pool;
2870d9a4ef3SDoug Ambrisko 	sc->request_msg_busaddr = sc->mfi_tb_busaddr + offset;
2880d9a4ef3SDoug Ambrisko 
2890d9a4ef3SDoug Ambrisko 	/* DJA XXX should this be bus dma ??? */
2900d9a4ef3SDoug Ambrisko 	/* Skip request message pool */
2910d9a4ef3SDoug Ambrisko 	addr = &addr[sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1)];
2920d9a4ef3SDoug Ambrisko 	/* Reply Frame Pool is initialized */
2930d9a4ef3SDoug Ambrisko 	sc->reply_frame_pool = (struct mfi_mpi2_reply_header *) addr;
2940d9a4ef3SDoug Ambrisko 	if (((uintptr_t)addr) & (0xFF)) {
2950d9a4ef3SDoug Ambrisko 		addr = &addr[sc->reply_size];
2960d9a4ef3SDoug Ambrisko 		addr = (uint8_t *)((uintptr_t)addr & (~0xFF));
2970d9a4ef3SDoug Ambrisko 	}
2980d9a4ef3SDoug Ambrisko 	sc->reply_frame_pool_align
2990d9a4ef3SDoug Ambrisko 		    = (struct mfi_mpi2_reply_header *)addr;
3000d9a4ef3SDoug Ambrisko 
3010d9a4ef3SDoug Ambrisko 	offset = (uintptr_t)sc->reply_frame_pool_align
3020d9a4ef3SDoug Ambrisko 	    - (uintptr_t)sc->request_message_pool;
3030d9a4ef3SDoug Ambrisko 	sc->reply_frame_busaddr = sc->mfi_tb_busaddr + offset;
3040d9a4ef3SDoug Ambrisko 
3050d9a4ef3SDoug Ambrisko 	/* Skip Reply Frame Pool */
3060d9a4ef3SDoug Ambrisko 	addr += sc->reply_size * sc->mfi_max_fw_cmds;
3070d9a4ef3SDoug Ambrisko 	sc->reply_pool_limit = addr;
3080d9a4ef3SDoug Ambrisko 
3090d9a4ef3SDoug Ambrisko 	/* initializing reply address to 0xFFFFFFFF */
3100d9a4ef3SDoug Ambrisko 	memset((uint8_t *)sc->reply_frame_pool, 0xFF,
3110d9a4ef3SDoug Ambrisko 	       (sc->reply_size * sc->mfi_max_fw_cmds));
3120d9a4ef3SDoug Ambrisko 
3130d9a4ef3SDoug Ambrisko 	offset = sc->reply_size * sc->mfi_max_fw_cmds;
3140d9a4ef3SDoug Ambrisko 	sc->sg_frame_busaddr = sc->reply_frame_busaddr + offset;
3150d9a4ef3SDoug Ambrisko 	/* initialize the last_reply_idx to 0 */
3160d9a4ef3SDoug Ambrisko 	sc->last_reply_idx = 0;
31708c89430SSteven Hartland 	MFI_WRITE4(sc, MFI_RFPI, sc->mfi_max_fw_cmds - 1);
31808c89430SSteven Hartland 	MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
3190d9a4ef3SDoug Ambrisko 	offset = (sc->sg_frame_busaddr + (MEGASAS_MAX_SZ_CHAIN_FRAME *
3200d9a4ef3SDoug Ambrisko 	    sc->mfi_max_fw_cmds)) - sc->mfi_tb_busaddr;
3210d9a4ef3SDoug Ambrisko 	if (offset > tbolt_contg_length)
3220d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Error:Initialized more than "
3230d9a4ef3SDoug Ambrisko 		    "allocated\n");
3240d9a4ef3SDoug Ambrisko 	return 0;
3250d9a4ef3SDoug Ambrisko }
3260d9a4ef3SDoug Ambrisko 
3270d9a4ef3SDoug Ambrisko /*
3280d9a4ef3SDoug Ambrisko  * This routine prepare and issue INIT2 frame to the Firmware
3290d9a4ef3SDoug Ambrisko  */
3300d9a4ef3SDoug Ambrisko 
3310d9a4ef3SDoug Ambrisko int
mfi_tbolt_init_MFI_queue(struct mfi_softc * sc)3320d9a4ef3SDoug Ambrisko mfi_tbolt_init_MFI_queue(struct mfi_softc *sc)
3330d9a4ef3SDoug Ambrisko {
3340d9a4ef3SDoug Ambrisko 	struct MPI2_IOC_INIT_REQUEST   *mpi2IocInit;
3350d9a4ef3SDoug Ambrisko 	struct mfi_init_frame		*mfi_init;
3360d9a4ef3SDoug Ambrisko 	uintptr_t			offset = 0;
337a6ba0fd6SDoug Ambrisko 	bus_addr_t			phyAddress;
3380d9a4ef3SDoug Ambrisko 	MFI_ADDRESS			*mfiAddressTemp;
33908c89430SSteven Hartland 	struct mfi_command		*cm, cmd_tmp;
3400d9a4ef3SDoug Ambrisko 	int error;
3410d9a4ef3SDoug Ambrisko 
34208c89430SSteven Hartland 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
34308c89430SSteven Hartland 
3440d9a4ef3SDoug Ambrisko 	/* Check if initialization is already completed */
3450d9a4ef3SDoug Ambrisko 	if (sc->MFA_enabled) {
34608c89430SSteven Hartland 		device_printf(sc->mfi_dev, "tbolt_init already initialised!\n");
3470d9a4ef3SDoug Ambrisko 		return 1;
3480d9a4ef3SDoug Ambrisko 	}
3490d9a4ef3SDoug Ambrisko 
3500d9a4ef3SDoug Ambrisko 	if ((cm = mfi_dequeue_free(sc)) == NULL) {
35108c89430SSteven Hartland 		device_printf(sc->mfi_dev, "tbolt_init failed to get command "
35208c89430SSteven Hartland 		    " entry!\n");
3530d9a4ef3SDoug Ambrisko 		return (EBUSY);
3540d9a4ef3SDoug Ambrisko 	}
35508c89430SSteven Hartland 
35608c89430SSteven Hartland 	cmd_tmp.cm_frame = cm->cm_frame;
35708c89430SSteven Hartland 	cmd_tmp.cm_frame_busaddr = cm->cm_frame_busaddr;
35808c89430SSteven Hartland 	cmd_tmp.cm_dmamap = cm->cm_dmamap;
35908c89430SSteven Hartland 
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 
3650d9a4ef3SDoug Ambrisko 	/*
3660d9a4ef3SDoug Ambrisko 	 * Abuse the SG list area of the frame to hold the init_qinfo
3670d9a4ef3SDoug Ambrisko 	 * object;
3680d9a4ef3SDoug Ambrisko 	 */
3690d9a4ef3SDoug Ambrisko 	mfi_init = &cm->cm_frame->init;
3700d9a4ef3SDoug Ambrisko 
37108c89430SSteven Hartland 	mpi2IocInit = (struct MPI2_IOC_INIT_REQUEST *)sc->mfi_tb_ioc_init_desc;
3720d9a4ef3SDoug Ambrisko 	bzero(mpi2IocInit, sizeof(struct MPI2_IOC_INIT_REQUEST));
3730d9a4ef3SDoug Ambrisko 	mpi2IocInit->Function  = MPI2_FUNCTION_IOC_INIT;
3740d9a4ef3SDoug Ambrisko 	mpi2IocInit->WhoInit   = MPI2_WHOINIT_HOST_DRIVER;
3750d9a4ef3SDoug Ambrisko 
3760d9a4ef3SDoug Ambrisko 	/* set MsgVersion and HeaderVersion host driver was built with */
3770d9a4ef3SDoug Ambrisko 	mpi2IocInit->MsgVersion = MPI2_VERSION;
3780d9a4ef3SDoug Ambrisko 	mpi2IocInit->HeaderVersion = MPI2_HEADER_VERSION;
3790d9a4ef3SDoug Ambrisko 	mpi2IocInit->SystemRequestFrameSize = sc->raid_io_msg_size/4;
3800d9a4ef3SDoug Ambrisko 	mpi2IocInit->ReplyDescriptorPostQueueDepth
3810d9a4ef3SDoug Ambrisko 	    = (uint16_t)sc->mfi_max_fw_cmds;
3820d9a4ef3SDoug Ambrisko 	mpi2IocInit->ReplyFreeQueueDepth = 0; /* Not supported by MR. */
3830d9a4ef3SDoug Ambrisko 
3840d9a4ef3SDoug Ambrisko 	/* Get physical address of reply frame pool */
3850d9a4ef3SDoug Ambrisko 	offset = (uintptr_t) sc->reply_frame_pool_align
3860d9a4ef3SDoug Ambrisko 	    - (uintptr_t)sc->request_message_pool;
3870d9a4ef3SDoug Ambrisko 	phyAddress = sc->mfi_tb_busaddr + offset;
3880d9a4ef3SDoug Ambrisko 	mfiAddressTemp =
3890d9a4ef3SDoug Ambrisko 	    (MFI_ADDRESS *)&mpi2IocInit->ReplyDescriptorPostQueueAddress;
390a6ba0fd6SDoug Ambrisko 	mfiAddressTemp->u.addressLow = (uint32_t)phyAddress;
391a6ba0fd6SDoug Ambrisko 	mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32);
3920d9a4ef3SDoug Ambrisko 
3930d9a4ef3SDoug Ambrisko 	/* Get physical address of request message pool */
3940d9a4ef3SDoug Ambrisko 	offset = sc->request_message_pool_align - sc->request_message_pool;
3950d9a4ef3SDoug Ambrisko 	phyAddress =  sc->mfi_tb_busaddr + offset;
3960d9a4ef3SDoug Ambrisko 	mfiAddressTemp = (MFI_ADDRESS *)&mpi2IocInit->SystemRequestFrameBaseAddress;
397a6ba0fd6SDoug Ambrisko 	mfiAddressTemp->u.addressLow = (uint32_t)phyAddress;
398a6ba0fd6SDoug Ambrisko 	mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32);
399a6ba0fd6SDoug Ambrisko 	mpi2IocInit->ReplyFreeQueueAddress =  0; /* Not supported by MR. */
4000d9a4ef3SDoug Ambrisko 	mpi2IocInit->TimeStamp = time_uptime;
4010d9a4ef3SDoug Ambrisko 
4020d9a4ef3SDoug Ambrisko 	if (sc->verbuf) {
4030d9a4ef3SDoug Ambrisko 		snprintf((char *)sc->verbuf, strlen(MEGASAS_VERSION) + 2, "%s\n",
4040d9a4ef3SDoug Ambrisko                 MEGASAS_VERSION);
405a6ba0fd6SDoug Ambrisko 		mfi_init->driver_ver_lo = (uint32_t)sc->verbuf_h_busaddr;
406a6ba0fd6SDoug Ambrisko 		mfi_init->driver_ver_hi =
407a6ba0fd6SDoug Ambrisko 		    (uint32_t)((uint64_t)sc->verbuf_h_busaddr >> 32);
4080d9a4ef3SDoug Ambrisko 	}
4090d9a4ef3SDoug Ambrisko 	/* Get the physical address of the mpi2 ioc init command */
4100d9a4ef3SDoug Ambrisko 	phyAddress =  sc->mfi_tb_ioc_init_busaddr;
411a6ba0fd6SDoug Ambrisko 	mfi_init->qinfo_new_addr_lo = (uint32_t)phyAddress;
412a6ba0fd6SDoug Ambrisko 	mfi_init->qinfo_new_addr_hi = (uint32_t)((uint64_t)phyAddress >> 32);
4130d9a4ef3SDoug Ambrisko 	mfi_init->header.flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
4140d9a4ef3SDoug Ambrisko 
4150d9a4ef3SDoug Ambrisko 	mfi_init->header.cmd = MFI_CMD_INIT;
4160d9a4ef3SDoug Ambrisko 	mfi_init->header.data_len = sizeof(struct MPI2_IOC_INIT_REQUEST);
4170d9a4ef3SDoug Ambrisko 	mfi_init->header.cmd_status = MFI_STAT_INVALID_STATUS;
4180d9a4ef3SDoug Ambrisko 
4190d9a4ef3SDoug Ambrisko 	cm->cm_data = NULL;
4200d9a4ef3SDoug Ambrisko 	cm->cm_flags |= MFI_CMD_POLLED;
4210d9a4ef3SDoug Ambrisko 	cm->cm_timestamp = time_uptime;
4220d9a4ef3SDoug Ambrisko 	if ((error = mfi_mapcmd(sc, cm)) != 0) {
4230d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "failed to send IOC init2 "
4240d9a4ef3SDoug Ambrisko 		    "command %d at %lx\n", error, (long)cm->cm_frame_busaddr);
42508c89430SSteven Hartland 		goto out;
4260d9a4ef3SDoug Ambrisko 	}
4270d9a4ef3SDoug Ambrisko 
42808c89430SSteven Hartland 	if (mfi_init->header.cmd_status == MFI_STAT_OK) {
4290d9a4ef3SDoug Ambrisko 		sc->MFA_enabled = 1;
43008c89430SSteven Hartland 	} else {
43108c89430SSteven Hartland 		device_printf(sc->mfi_dev, "Init command Failed %#x\n",
4320d9a4ef3SDoug Ambrisko 		    mfi_init->header.cmd_status);
43308c89430SSteven Hartland 		error = mfi_init->header.cmd_status;
43408c89430SSteven Hartland 		goto out;
4350d9a4ef3SDoug Ambrisko 	}
4360d9a4ef3SDoug Ambrisko 
43708c89430SSteven Hartland out:
43808c89430SSteven Hartland 	cm->cm_frame = cmd_tmp.cm_frame;
43908c89430SSteven Hartland 	cm->cm_frame_busaddr = cmd_tmp.cm_frame_busaddr;
44008c89430SSteven Hartland 	cm->cm_dmamap = cmd_tmp.cm_dmamap;
44108c89430SSteven Hartland 	mfi_release_command(cm);
44208c89430SSteven Hartland 
44308c89430SSteven Hartland 	return (error);
4440d9a4ef3SDoug Ambrisko 
4450d9a4ef3SDoug Ambrisko }
4460d9a4ef3SDoug Ambrisko 
44752d5baa2SDoug Ambrisko int
mfi_tbolt_alloc_cmd(struct mfi_softc * sc)44852d5baa2SDoug Ambrisko mfi_tbolt_alloc_cmd(struct mfi_softc *sc)
4490d9a4ef3SDoug Ambrisko {
4500d9a4ef3SDoug Ambrisko 	struct mfi_cmd_tbolt *cmd;
451a6ba0fd6SDoug Ambrisko 	bus_addr_t io_req_base_phys;
4520d9a4ef3SDoug Ambrisko 	uint8_t *io_req_base;
453a6ba0fd6SDoug Ambrisko 	int i = 0, j = 0, offset = 0;
4540d9a4ef3SDoug Ambrisko 
4550d9a4ef3SDoug Ambrisko 	/*
4560d9a4ef3SDoug Ambrisko 	 * sc->mfi_cmd_pool_tbolt is an array of struct mfi_cmd_tbolt pointers.
4570d9a4ef3SDoug Ambrisko 	 * Allocate the dynamic array first and then allocate individual
4580d9a4ef3SDoug Ambrisko 	 * commands.
4590d9a4ef3SDoug Ambrisko 	 */
4600d9a4ef3SDoug Ambrisko 	sc->request_desc_pool = malloc(sizeof(
4610d9a4ef3SDoug Ambrisko 	    union mfi_mpi2_request_descriptor) * sc->mfi_max_fw_cmds,
4620d9a4ef3SDoug Ambrisko 	    M_MFIBUF, M_NOWAIT|M_ZERO);
46308c89430SSteven Hartland 
46408c89430SSteven Hartland 	if (sc->request_desc_pool == NULL) {
46508c89430SSteven Hartland 		device_printf(sc->mfi_dev, "Could not alloc "
46608c89430SSteven Hartland 		    "memory for request_desc_pool\n");
46708c89430SSteven Hartland 		return (ENOMEM);
46808c89430SSteven Hartland 	}
46908c89430SSteven Hartland 
4700d9a4ef3SDoug Ambrisko 	sc->mfi_cmd_pool_tbolt = malloc(sizeof(struct mfi_cmd_tbolt*)
4710d9a4ef3SDoug Ambrisko 	    * sc->mfi_max_fw_cmds, M_MFIBUF, M_NOWAIT|M_ZERO);
4720d9a4ef3SDoug Ambrisko 
47308c89430SSteven Hartland 	if (sc->mfi_cmd_pool_tbolt == NULL) {
47408c89430SSteven Hartland 		free(sc->request_desc_pool, M_MFIBUF);
47508c89430SSteven Hartland 		device_printf(sc->mfi_dev, "Could not alloc "
47608c89430SSteven Hartland 		    "memory for cmd_pool_tbolt\n");
47708c89430SSteven Hartland 		return (ENOMEM);
4780d9a4ef3SDoug Ambrisko 	}
4790d9a4ef3SDoug Ambrisko 
4800d9a4ef3SDoug Ambrisko 	for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
4810d9a4ef3SDoug Ambrisko 		sc->mfi_cmd_pool_tbolt[i] = malloc(sizeof(
4820d9a4ef3SDoug Ambrisko 		    struct mfi_cmd_tbolt),M_MFIBUF, M_NOWAIT|M_ZERO);
4830d9a4ef3SDoug Ambrisko 
4840d9a4ef3SDoug Ambrisko 		if (!sc->mfi_cmd_pool_tbolt[i]) {
48508c89430SSteven Hartland 			device_printf(sc->mfi_dev, "Could not alloc "
48608c89430SSteven Hartland 			    "cmd_pool_tbolt entry\n");
4870d9a4ef3SDoug Ambrisko 
4880d9a4ef3SDoug Ambrisko 			for (j = 0; j < i; j++)
4890d9a4ef3SDoug Ambrisko 				free(sc->mfi_cmd_pool_tbolt[j], M_MFIBUF);
4900d9a4ef3SDoug Ambrisko 
49108c89430SSteven Hartland 			free(sc->request_desc_pool, M_MFIBUF);
49208c89430SSteven Hartland 			sc->request_desc_pool = NULL;
4930d9a4ef3SDoug Ambrisko 			free(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
4940d9a4ef3SDoug Ambrisko 			sc->mfi_cmd_pool_tbolt = NULL;
49508c89430SSteven Hartland 
49608c89430SSteven Hartland 			return (ENOMEM);
4970d9a4ef3SDoug Ambrisko 		}
4980d9a4ef3SDoug Ambrisko 	}
4990d9a4ef3SDoug Ambrisko 
5000d9a4ef3SDoug Ambrisko 	/*
5010d9a4ef3SDoug Ambrisko 	 * The first 256 bytes (SMID 0) is not used. Don't add to the cmd
5020d9a4ef3SDoug Ambrisko 	 * list
5030d9a4ef3SDoug Ambrisko 	 */
5040d9a4ef3SDoug Ambrisko 	io_req_base = sc->request_message_pool_align
5050d9a4ef3SDoug Ambrisko 		+ MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
5060d9a4ef3SDoug Ambrisko 	io_req_base_phys = sc->request_msg_busaddr
5070d9a4ef3SDoug Ambrisko 		+ MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
5080d9a4ef3SDoug Ambrisko 
5090d9a4ef3SDoug Ambrisko 	/*
5100d9a4ef3SDoug Ambrisko 	 * Add all the commands to command pool (instance->cmd_pool)
5110d9a4ef3SDoug Ambrisko 	 */
5120d9a4ef3SDoug Ambrisko 	/* SMID 0 is reserved. Set SMID/index from 1 */
5130d9a4ef3SDoug Ambrisko 
5140d9a4ef3SDoug Ambrisko 	for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
5150d9a4ef3SDoug Ambrisko 		cmd = sc->mfi_cmd_pool_tbolt[i];
5160d9a4ef3SDoug Ambrisko 		offset = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * i;
5170d9a4ef3SDoug Ambrisko 		cmd->index = i + 1;
5180d9a4ef3SDoug Ambrisko 		cmd->request_desc = (union mfi_mpi2_request_descriptor *)
5190d9a4ef3SDoug Ambrisko 		    (sc->request_desc_pool + i);
5200d9a4ef3SDoug Ambrisko 		cmd->io_request = (struct mfi_mpi2_request_raid_scsi_io *)
5210d9a4ef3SDoug Ambrisko 		    (io_req_base + offset);
5220d9a4ef3SDoug Ambrisko 		cmd->io_request_phys_addr = io_req_base_phys + offset;
5230d9a4ef3SDoug Ambrisko 		cmd->sg_frame = (MPI2_SGE_IO_UNION *)(sc->reply_pool_limit
5240d9a4ef3SDoug Ambrisko 		    + i * MEGASAS_MAX_SZ_CHAIN_FRAME);
5250d9a4ef3SDoug Ambrisko 		cmd->sg_frame_phys_addr = sc->sg_frame_busaddr + i
5260d9a4ef3SDoug Ambrisko 		    * MEGASAS_MAX_SZ_CHAIN_FRAME;
52758ef3154SDoug Ambrisko 		cmd->sync_cmd_idx = sc->mfi_max_fw_cmds;
5280d9a4ef3SDoug Ambrisko 
5290d9a4ef3SDoug Ambrisko 		TAILQ_INSERT_TAIL(&(sc->mfi_cmd_tbolt_tqh), cmd, next);
5300d9a4ef3SDoug Ambrisko 	}
5310d9a4ef3SDoug Ambrisko 	return 0;
5320d9a4ef3SDoug Ambrisko }
5330d9a4ef3SDoug Ambrisko 
53452d5baa2SDoug Ambrisko int
mfi_tbolt_reset(struct mfi_softc * sc)53552d5baa2SDoug Ambrisko mfi_tbolt_reset(struct mfi_softc *sc)
5360d9a4ef3SDoug Ambrisko {
5370d9a4ef3SDoug Ambrisko 	uint32_t fw_state;
5380d9a4ef3SDoug Ambrisko 
5390d9a4ef3SDoug Ambrisko 	mtx_lock(&sc->mfi_io_lock);
5400d9a4ef3SDoug Ambrisko 	if (sc->hw_crit_error) {
5410d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "HW CRITICAL ERROR\n");
5420d9a4ef3SDoug Ambrisko 		mtx_unlock(&sc->mfi_io_lock);
5430d9a4ef3SDoug Ambrisko 		return 1;
5440d9a4ef3SDoug Ambrisko 	}
5450d9a4ef3SDoug Ambrisko 
5460d9a4ef3SDoug Ambrisko 	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
5470d9a4ef3SDoug Ambrisko 		fw_state = sc->mfi_read_fw_status(sc);
54808c89430SSteven Hartland 		if ((fw_state & MFI_FWSTATE_FAULT) == MFI_FWSTATE_FAULT ||
54908c89430SSteven Hartland 		    mfi_fw_reset_test) {
5500d9a4ef3SDoug Ambrisko 			if ((sc->disableOnlineCtrlReset == 0)
5510d9a4ef3SDoug Ambrisko 			    && (sc->adpreset == 0)) {
5520d9a4ef3SDoug Ambrisko 				device_printf(sc->mfi_dev, "Adapter RESET "
5530d9a4ef3SDoug Ambrisko 				    "condition is detected\n");
5540d9a4ef3SDoug Ambrisko 				sc->adpreset = 1;
5550d9a4ef3SDoug Ambrisko 				sc->issuepend_done = 0;
5560d9a4ef3SDoug Ambrisko 				sc->MFA_enabled = 0;
5570d9a4ef3SDoug Ambrisko 				sc->last_reply_idx = 0;
5580d9a4ef3SDoug Ambrisko 				mfi_process_fw_state_chg_isr((void *) sc);
5590d9a4ef3SDoug Ambrisko 			}
5600d9a4ef3SDoug Ambrisko 			mtx_unlock(&sc->mfi_io_lock);
5610d9a4ef3SDoug Ambrisko 			return 0;
5620d9a4ef3SDoug Ambrisko 		}
5630d9a4ef3SDoug Ambrisko 	}
5640d9a4ef3SDoug Ambrisko 	mtx_unlock(&sc->mfi_io_lock);
5650d9a4ef3SDoug Ambrisko 	return 1;
5660d9a4ef3SDoug Ambrisko }
5670d9a4ef3SDoug Ambrisko 
5680d9a4ef3SDoug Ambrisko /*
5690d9a4ef3SDoug Ambrisko  * mfi_intr_tbolt - isr entry point
5700d9a4ef3SDoug Ambrisko  */
57152d5baa2SDoug Ambrisko void
mfi_intr_tbolt(void * arg)57252d5baa2SDoug Ambrisko mfi_intr_tbolt(void *arg)
5730d9a4ef3SDoug Ambrisko {
5740d9a4ef3SDoug Ambrisko 	struct mfi_softc *sc = (struct mfi_softc *)arg;
5750d9a4ef3SDoug Ambrisko 
576a6ba0fd6SDoug Ambrisko 	if (sc->mfi_check_clear_intr(sc) == 1) {
5770d9a4ef3SDoug Ambrisko 		return;
5780d9a4ef3SDoug Ambrisko 	}
579a6ba0fd6SDoug Ambrisko 	if (sc->mfi_detaching)
5800d9a4ef3SDoug Ambrisko 		return;
5810d9a4ef3SDoug Ambrisko 	mtx_lock(&sc->mfi_io_lock);
5820d9a4ef3SDoug Ambrisko 	mfi_tbolt_complete_cmd(sc);
5830d9a4ef3SDoug Ambrisko 	sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
5840d9a4ef3SDoug Ambrisko 	mfi_startio(sc);
5850d9a4ef3SDoug Ambrisko 	mtx_unlock(&sc->mfi_io_lock);
5860d9a4ef3SDoug Ambrisko 	return;
5870d9a4ef3SDoug Ambrisko }
5880d9a4ef3SDoug Ambrisko 
58952d5baa2SDoug Ambrisko /*
5900d9a4ef3SDoug Ambrisko  * map_cmd_status -	Maps FW cmd status to OS cmd status
5910d9a4ef3SDoug Ambrisko  * @cmd :		Pointer to cmd
5920d9a4ef3SDoug Ambrisko  * @status :		status of cmd returned by FW
5930d9a4ef3SDoug Ambrisko  * @ext_status :	ext status of cmd returned by FW
5940d9a4ef3SDoug Ambrisko  */
5950d9a4ef3SDoug Ambrisko 
5960d9a4ef3SDoug Ambrisko void
map_tbolt_cmd_status(struct mfi_command * mfi_cmd,uint8_t status,uint8_t ext_status)5970d9a4ef3SDoug Ambrisko map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status,
5980d9a4ef3SDoug Ambrisko     uint8_t ext_status)
5990d9a4ef3SDoug Ambrisko {
6000d9a4ef3SDoug Ambrisko 	switch (status) {
6010d9a4ef3SDoug Ambrisko 	case MFI_STAT_OK:
60258ef3154SDoug Ambrisko 		mfi_cmd->cm_frame->header.cmd_status = MFI_STAT_OK;
60358ef3154SDoug Ambrisko 		mfi_cmd->cm_frame->dcmd.header.cmd_status = MFI_STAT_OK;
60458ef3154SDoug Ambrisko 		mfi_cmd->cm_error = MFI_STAT_OK;
6050d9a4ef3SDoug Ambrisko 		break;
6060d9a4ef3SDoug Ambrisko 
6070d9a4ef3SDoug Ambrisko 	case MFI_STAT_SCSI_IO_FAILED:
6080d9a4ef3SDoug Ambrisko 	case MFI_STAT_LD_INIT_IN_PROGRESS:
6090d9a4ef3SDoug Ambrisko 		mfi_cmd->cm_frame->header.cmd_status = status;
6100d9a4ef3SDoug Ambrisko 		mfi_cmd->cm_frame->header.scsi_status = ext_status;
6110d9a4ef3SDoug Ambrisko 		mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
6120d9a4ef3SDoug Ambrisko 		mfi_cmd->cm_frame->dcmd.header.scsi_status
6130d9a4ef3SDoug Ambrisko 		    = ext_status;
6140d9a4ef3SDoug Ambrisko 		break;
6150d9a4ef3SDoug Ambrisko 
6160d9a4ef3SDoug Ambrisko 	case MFI_STAT_SCSI_DONE_WITH_ERROR:
6170d9a4ef3SDoug Ambrisko 		mfi_cmd->cm_frame->header.cmd_status = ext_status;
6180d9a4ef3SDoug Ambrisko 		mfi_cmd->cm_frame->dcmd.header.cmd_status = ext_status;
6190d9a4ef3SDoug Ambrisko 		break;
6200d9a4ef3SDoug Ambrisko 
6210d9a4ef3SDoug Ambrisko 	case MFI_STAT_LD_OFFLINE:
6220d9a4ef3SDoug Ambrisko 	case MFI_STAT_DEVICE_NOT_FOUND:
6230d9a4ef3SDoug Ambrisko 		mfi_cmd->cm_frame->header.cmd_status = status;
6240d9a4ef3SDoug Ambrisko 		mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
6250d9a4ef3SDoug Ambrisko 		break;
6260d9a4ef3SDoug Ambrisko 
6270d9a4ef3SDoug Ambrisko 	default:
6280d9a4ef3SDoug Ambrisko 		mfi_cmd->cm_frame->header.cmd_status = status;
6290d9a4ef3SDoug Ambrisko 		mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
6300d9a4ef3SDoug Ambrisko 		break;
6310d9a4ef3SDoug Ambrisko 	}
6320d9a4ef3SDoug Ambrisko }
6330d9a4ef3SDoug Ambrisko 
63452d5baa2SDoug Ambrisko /*
635a6ba0fd6SDoug Ambrisko  * mfi_tbolt_return_cmd -	Return a cmd to free command pool
636a6ba0fd6SDoug Ambrisko  * @instance:		Adapter soft state
63708c89430SSteven Hartland  * @tbolt_cmd:		Tbolt command packet to be returned to free command pool
63808c89430SSteven Hartland  * @mfi_cmd:		Oning MFI command packe
639a6ba0fd6SDoug Ambrisko  */
64008c89430SSteven Hartland void
mfi_tbolt_return_cmd(struct mfi_softc * sc,struct mfi_cmd_tbolt * tbolt_cmd,struct mfi_command * mfi_cmd)64108c89430SSteven Hartland mfi_tbolt_return_cmd(struct mfi_softc *sc, struct mfi_cmd_tbolt *tbolt_cmd,
64208c89430SSteven Hartland     struct mfi_command *mfi_cmd)
643a6ba0fd6SDoug Ambrisko {
644a6ba0fd6SDoug Ambrisko 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
6450d9a4ef3SDoug Ambrisko 
64608c89430SSteven Hartland 	mfi_cmd->cm_flags &= ~MFI_CMD_TBOLT;
64708c89430SSteven Hartland 	mfi_cmd->cm_extra_frames = 0;
64808c89430SSteven Hartland 	tbolt_cmd->sync_cmd_idx = sc->mfi_max_fw_cmds;
64908c89430SSteven Hartland 
65008c89430SSteven Hartland 	TAILQ_INSERT_TAIL(&sc->mfi_cmd_tbolt_tqh, tbolt_cmd, next);
651a6ba0fd6SDoug Ambrisko }
6520d9a4ef3SDoug Ambrisko 
653ddbffe7fSDoug Ambrisko void
mfi_tbolt_complete_cmd(struct mfi_softc * sc)654ddbffe7fSDoug Ambrisko mfi_tbolt_complete_cmd(struct mfi_softc *sc)
6550d9a4ef3SDoug Ambrisko {
6560d9a4ef3SDoug Ambrisko 	struct mfi_mpi2_reply_header *desc, *reply_desc;
65708c89430SSteven Hartland 	struct mfi_command *cmd_mfi;	/* For MFA Cmds */
6580d9a4ef3SDoug Ambrisko 	struct mfi_cmd_tbolt *cmd_tbolt;
6590d9a4ef3SDoug Ambrisko 	uint16_t smid;
6600d9a4ef3SDoug Ambrisko 	uint8_t reply_descript_type;
6610d9a4ef3SDoug Ambrisko 	uint32_t status, extStatus;
6620d9a4ef3SDoug Ambrisko 	uint16_t num_completed;
6630d9a4ef3SDoug Ambrisko 	union desc_value val;
66408c89430SSteven Hartland 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
6650d9a4ef3SDoug Ambrisko 
6660d9a4ef3SDoug Ambrisko 	desc = (struct mfi_mpi2_reply_header *)
6670d9a4ef3SDoug Ambrisko 		((uintptr_t)sc->reply_frame_pool_align
6680d9a4ef3SDoug Ambrisko 		+ sc->last_reply_idx * sc->reply_size);
6690d9a4ef3SDoug Ambrisko 	reply_desc = desc;
6700d9a4ef3SDoug Ambrisko 
67108c89430SSteven Hartland 	if (reply_desc == NULL) {
6720d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "reply desc is NULL!!\n");
67308c89430SSteven Hartland 		return;
67408c89430SSteven Hartland 	}
6750d9a4ef3SDoug Ambrisko 
6760d9a4ef3SDoug Ambrisko 	reply_descript_type = reply_desc->ReplyFlags
6770d9a4ef3SDoug Ambrisko 	     & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
6780d9a4ef3SDoug Ambrisko 	if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
6790d9a4ef3SDoug Ambrisko 		return;
6800d9a4ef3SDoug Ambrisko 
6810d9a4ef3SDoug Ambrisko 	num_completed = 0;
6820d9a4ef3SDoug Ambrisko 	val.word = ((union mfi_mpi2_reply_descriptor *)desc)->words;
6830d9a4ef3SDoug Ambrisko 
6840d9a4ef3SDoug Ambrisko 	/* Read Reply descriptor */
6850d9a4ef3SDoug Ambrisko 	while ((val.u.low != 0xFFFFFFFF) && (val.u.high != 0xFFFFFFFF)) {
6860d9a4ef3SDoug Ambrisko 		smid = reply_desc->SMID;
68708c89430SSteven Hartland 		if (smid == 0 || smid > sc->mfi_max_fw_cmds) {
68808c89430SSteven Hartland 			device_printf(sc->mfi_dev, "smid is %d cannot "
68908c89430SSteven Hartland 			    "proceed - skipping\n", smid);
69008c89430SSteven Hartland 			goto next;
6910d9a4ef3SDoug Ambrisko 		}
6920d9a4ef3SDoug Ambrisko 		cmd_tbolt = sc->mfi_cmd_pool_tbolt[smid - 1];
69308c89430SSteven Hartland 		if (cmd_tbolt->sync_cmd_idx == sc->mfi_max_fw_cmds) {
69408c89430SSteven Hartland 			device_printf(sc->mfi_dev, "cmd_tbolt %p "
69508c89430SSteven Hartland 			    "has invalid sync_cmd_idx=%d - skipping\n",
69608c89430SSteven Hartland 			    cmd_tbolt, cmd_tbolt->sync_cmd_idx);
69708c89430SSteven Hartland 			goto next;
69808c89430SSteven Hartland 		}
6990d9a4ef3SDoug Ambrisko 		cmd_mfi = &sc->mfi_commands[cmd_tbolt->sync_cmd_idx];
7000d9a4ef3SDoug Ambrisko 
7010d9a4ef3SDoug Ambrisko 		status = cmd_mfi->cm_frame->dcmd.header.cmd_status;
7020d9a4ef3SDoug Ambrisko 		extStatus = cmd_mfi->cm_frame->dcmd.header.scsi_status;
7030d9a4ef3SDoug Ambrisko 		map_tbolt_cmd_status(cmd_mfi, status, extStatus);
704ddbffe7fSDoug Ambrisko 
70508c89430SSteven Hartland 		/* mfi_tbolt_return_cmd is handled by mfi complete / return */
70608c89430SSteven Hartland 		if ((cmd_mfi->cm_flags & MFI_CMD_SCSI) != 0 &&
70758ef3154SDoug Ambrisko 		    (cmd_mfi->cm_flags & MFI_CMD_POLLED) != 0) {
70858ef3154SDoug Ambrisko 			/* polled LD/SYSPD IO command */
70958ef3154SDoug Ambrisko 			/* XXX mark okay for now DJA */
71058ef3154SDoug Ambrisko 			cmd_mfi->cm_frame->header.cmd_status = MFI_STAT_OK;
71158ef3154SDoug Ambrisko 
71208c89430SSteven Hartland 		} else {
713ddbffe7fSDoug Ambrisko 			/* remove command from busy queue if not polled */
71408c89430SSteven Hartland 			if ((cmd_mfi->cm_flags & MFI_ON_MFIQ_BUSY) != 0)
7150d9a4ef3SDoug Ambrisko 				mfi_remove_busy(cmd_mfi);
71658ef3154SDoug Ambrisko 
71758ef3154SDoug Ambrisko 			/* complete the command */
718ddbffe7fSDoug Ambrisko 			mfi_complete(sc, cmd_mfi);
71958ef3154SDoug Ambrisko 		}
7200d9a4ef3SDoug Ambrisko 
72108c89430SSteven Hartland next:
7220d9a4ef3SDoug Ambrisko 		sc->last_reply_idx++;
7230d9a4ef3SDoug Ambrisko 		if (sc->last_reply_idx >= sc->mfi_max_fw_cmds) {
7240d9a4ef3SDoug Ambrisko 			MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
7250d9a4ef3SDoug Ambrisko 			sc->last_reply_idx = 0;
7260d9a4ef3SDoug Ambrisko 		}
72708c89430SSteven Hartland 
72808c89430SSteven Hartland 		/* Set it back to all 0xfff */
7290d9a4ef3SDoug Ambrisko 		((union mfi_mpi2_reply_descriptor*)desc)->words =
7300d9a4ef3SDoug Ambrisko 			~((uint64_t)0x00);
7310d9a4ef3SDoug Ambrisko 
7320d9a4ef3SDoug Ambrisko 		num_completed++;
7330d9a4ef3SDoug Ambrisko 
7340d9a4ef3SDoug Ambrisko 		/* Get the next reply descriptor */
7350d9a4ef3SDoug Ambrisko 		desc = (struct mfi_mpi2_reply_header *)
7360d9a4ef3SDoug Ambrisko 		    ((uintptr_t)sc->reply_frame_pool_align
7370d9a4ef3SDoug Ambrisko 		    + sc->last_reply_idx * sc->reply_size);
7380d9a4ef3SDoug Ambrisko 		reply_desc = desc;
7390d9a4ef3SDoug Ambrisko 		val.word = ((union mfi_mpi2_reply_descriptor*)desc)->words;
7400d9a4ef3SDoug Ambrisko 		reply_descript_type = reply_desc->ReplyFlags
7410d9a4ef3SDoug Ambrisko 		    & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
7420d9a4ef3SDoug Ambrisko 		if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
7430d9a4ef3SDoug Ambrisko 			break;
7440d9a4ef3SDoug Ambrisko 	}
7450d9a4ef3SDoug Ambrisko 
7460d9a4ef3SDoug Ambrisko 	if (!num_completed)
7470d9a4ef3SDoug Ambrisko 		return;
7480d9a4ef3SDoug Ambrisko 
7490d9a4ef3SDoug Ambrisko 	/* update replyIndex to FW */
7500d9a4ef3SDoug Ambrisko 	if (sc->last_reply_idx)
7510d9a4ef3SDoug Ambrisko 		MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
7520d9a4ef3SDoug Ambrisko 
7530d9a4ef3SDoug Ambrisko 	return;
7540d9a4ef3SDoug Ambrisko }
7550d9a4ef3SDoug Ambrisko 
75652d5baa2SDoug Ambrisko /*
7570d9a4ef3SDoug Ambrisko  * mfi_get_cmd -	Get a command from the free pool
7580d9a4ef3SDoug Ambrisko  * @instance:		Adapter soft state
7590d9a4ef3SDoug Ambrisko  *
7600d9a4ef3SDoug Ambrisko  * Returns a free command from the pool
7610d9a4ef3SDoug Ambrisko  */
7620d9a4ef3SDoug Ambrisko 
76352d5baa2SDoug Ambrisko struct mfi_cmd_tbolt *
mfi_tbolt_get_cmd(struct mfi_softc * sc,struct mfi_command * mfi_cmd)76408c89430SSteven Hartland mfi_tbolt_get_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd)
7650d9a4ef3SDoug Ambrisko {
7660d9a4ef3SDoug Ambrisko 	struct mfi_cmd_tbolt *cmd = NULL;
7670d9a4ef3SDoug Ambrisko 
7680d9a4ef3SDoug Ambrisko 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
7690d9a4ef3SDoug Ambrisko 
77008c89430SSteven Hartland 	if ((cmd = TAILQ_FIRST(&sc->mfi_cmd_tbolt_tqh)) == NULL)
77108c89430SSteven Hartland 		return (NULL);
7720d9a4ef3SDoug Ambrisko 	TAILQ_REMOVE(&sc->mfi_cmd_tbolt_tqh, cmd, next);
7730d9a4ef3SDoug Ambrisko 	memset((uint8_t *)cmd->sg_frame, 0, MEGASAS_MAX_SZ_CHAIN_FRAME);
7740d9a4ef3SDoug Ambrisko 	memset((uint8_t *)cmd->io_request, 0,
7750d9a4ef3SDoug Ambrisko 	    MEGASAS_THUNDERBOLT_NEW_MSG_SIZE);
77608c89430SSteven Hartland 
77708c89430SSteven Hartland 	cmd->sync_cmd_idx = mfi_cmd->cm_index;
77808c89430SSteven Hartland 	mfi_cmd->cm_extra_frames = cmd->index; /* Frame count used as SMID */
77908c89430SSteven Hartland 	mfi_cmd->cm_flags |= MFI_CMD_TBOLT;
78008c89430SSteven Hartland 
7810d9a4ef3SDoug Ambrisko 	return cmd;
7820d9a4ef3SDoug Ambrisko }
7830d9a4ef3SDoug Ambrisko 
7840d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *
mfi_tbolt_get_request_descriptor(struct mfi_softc * sc,uint16_t index)7850d9a4ef3SDoug Ambrisko mfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index)
7860d9a4ef3SDoug Ambrisko {
7870d9a4ef3SDoug Ambrisko 	uint8_t *p;
7880d9a4ef3SDoug Ambrisko 
7890d9a4ef3SDoug Ambrisko 	if (index >= sc->mfi_max_fw_cmds) {
7900d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Invalid SMID (0x%x)request "
7910d9a4ef3SDoug Ambrisko 		    "for descriptor\n", index);
7920d9a4ef3SDoug Ambrisko 		return NULL;
7930d9a4ef3SDoug Ambrisko 	}
7940d9a4ef3SDoug Ambrisko 	p = sc->request_desc_pool + sizeof(union mfi_mpi2_request_descriptor)
7950d9a4ef3SDoug Ambrisko 	    * index;
7960d9a4ef3SDoug Ambrisko 	memset(p, 0, sizeof(union mfi_mpi2_request_descriptor));
7970d9a4ef3SDoug Ambrisko 	return (union mfi_mpi2_request_descriptor *)p;
7980d9a4ef3SDoug Ambrisko }
7990d9a4ef3SDoug Ambrisko 
800a6ba0fd6SDoug Ambrisko /* Used to build IOCTL cmd */
8010d9a4ef3SDoug Ambrisko uint8_t
mfi_build_mpt_pass_thru(struct mfi_softc * sc,struct mfi_command * mfi_cmd)8020d9a4ef3SDoug Ambrisko mfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd)
8030d9a4ef3SDoug Ambrisko {
8040d9a4ef3SDoug Ambrisko 	MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain;
8050d9a4ef3SDoug Ambrisko 	struct mfi_mpi2_request_raid_scsi_io *io_req;
8060d9a4ef3SDoug Ambrisko 	struct mfi_cmd_tbolt *cmd;
8070d9a4ef3SDoug Ambrisko 
80808c89430SSteven Hartland 	cmd = mfi_tbolt_get_cmd(sc, mfi_cmd);
8090d9a4ef3SDoug Ambrisko 	if (!cmd)
8100d9a4ef3SDoug Ambrisko 		return EBUSY;
8110d9a4ef3SDoug Ambrisko 	io_req = cmd->io_request;
8120d9a4ef3SDoug Ambrisko 	mpi25_ieee_chain = (MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;
8130d9a4ef3SDoug Ambrisko 
8140d9a4ef3SDoug Ambrisko 	io_req->Function = MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
8150d9a4ef3SDoug Ambrisko 	io_req->SGLOffset0 = offsetof(struct mfi_mpi2_request_raid_scsi_io,
8160d9a4ef3SDoug Ambrisko 	    SGL) / 4;
8170d9a4ef3SDoug Ambrisko 	io_req->ChainOffset = sc->chain_offset_value_for_mpt_ptmsg;
8180d9a4ef3SDoug Ambrisko 
8190d9a4ef3SDoug Ambrisko 	mpi25_ieee_chain->Address = mfi_cmd->cm_frame_busaddr;
8200d9a4ef3SDoug Ambrisko 
8210d9a4ef3SDoug Ambrisko 	/*
8220d9a4ef3SDoug Ambrisko 	  In MFI pass thru, nextChainOffset will always be zero to
8230d9a4ef3SDoug Ambrisko 	  indicate the end of the chain.
8240d9a4ef3SDoug Ambrisko 	*/
8250d9a4ef3SDoug Ambrisko 	mpi25_ieee_chain->Flags= MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT
8260d9a4ef3SDoug Ambrisko 		| MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
8270d9a4ef3SDoug Ambrisko 
8280d9a4ef3SDoug Ambrisko 	/* setting the length to the maximum length */
8290d9a4ef3SDoug Ambrisko 	mpi25_ieee_chain->Length = 1024;
8300d9a4ef3SDoug Ambrisko 
8310d9a4ef3SDoug Ambrisko 	return 0;
8320d9a4ef3SDoug Ambrisko }
8330d9a4ef3SDoug Ambrisko 
8340d9a4ef3SDoug Ambrisko void
mfi_tbolt_build_ldio(struct mfi_softc * sc,struct mfi_command * mfi_cmd,struct mfi_cmd_tbolt * cmd)8350d9a4ef3SDoug Ambrisko mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
8360d9a4ef3SDoug Ambrisko     struct mfi_cmd_tbolt *cmd)
8370d9a4ef3SDoug Ambrisko {
8380d9a4ef3SDoug Ambrisko 	uint32_t start_lba_lo = 0, start_lba_hi = 0, device_id;
8390d9a4ef3SDoug Ambrisko 	struct mfi_mpi2_request_raid_scsi_io	*io_request;
8400d9a4ef3SDoug Ambrisko 	struct IO_REQUEST_INFO io_info;
8410d9a4ef3SDoug Ambrisko 
8420d9a4ef3SDoug Ambrisko 	device_id = mfi_cmd->cm_frame->io.header.target_id;
8430d9a4ef3SDoug Ambrisko 	io_request = cmd->io_request;
8440d9a4ef3SDoug Ambrisko 	io_request->RaidContext.TargetID = device_id;
8450d9a4ef3SDoug Ambrisko 	io_request->RaidContext.Status = 0;
8460d9a4ef3SDoug Ambrisko 	io_request->RaidContext.exStatus = 0;
8473b8ad66eSMark Johnston 	io_request->RaidContext.regLockFlags = 0;
8480d9a4ef3SDoug Ambrisko 
8490d9a4ef3SDoug Ambrisko 	start_lba_lo = mfi_cmd->cm_frame->io.lba_lo;
8500d9a4ef3SDoug Ambrisko 	start_lba_hi = mfi_cmd->cm_frame->io.lba_hi;
8510d9a4ef3SDoug Ambrisko 
8520d9a4ef3SDoug Ambrisko 	memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO));
8530d9a4ef3SDoug Ambrisko 	io_info.ldStartBlock = ((uint64_t)start_lba_hi << 32) | start_lba_lo;
8540d9a4ef3SDoug Ambrisko 	io_info.numBlocks = mfi_cmd->cm_frame->io.header.data_len;
8550d9a4ef3SDoug Ambrisko 	io_info.ldTgtId = device_id;
8560d9a4ef3SDoug Ambrisko 	if ((mfi_cmd->cm_frame->header.flags & MFI_FRAME_DIR_READ) ==
8570d9a4ef3SDoug Ambrisko 	    MFI_FRAME_DIR_READ)
8580d9a4ef3SDoug Ambrisko 		io_info.isRead = 1;
8590d9a4ef3SDoug Ambrisko 
8600d9a4ef3SDoug Ambrisko 	io_request->RaidContext.timeoutValue
8610d9a4ef3SDoug Ambrisko 		= MFI_FUSION_FP_DEFAULT_TIMEOUT;
8620d9a4ef3SDoug Ambrisko 	io_request->Function = MPI2_FUNCTION_LD_IO_REQUEST;
8630d9a4ef3SDoug Ambrisko 	io_request->DevHandle = device_id;
8640d9a4ef3SDoug Ambrisko 	cmd->request_desc->header.RequestFlags
8650d9a4ef3SDoug Ambrisko 		= (MFI_REQ_DESCRIPT_FLAGS_LD_IO
8660d9a4ef3SDoug Ambrisko 		   << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
8670d9a4ef3SDoug Ambrisko 	if ((io_request->IoFlags == 6) && (io_info.numBlocks == 0))
8680d9a4ef3SDoug Ambrisko 		io_request->RaidContext.RegLockLength = 0x100;
8690d9a4ef3SDoug Ambrisko 	io_request->DataLength = mfi_cmd->cm_frame->io.header.data_len
8700d9a4ef3SDoug Ambrisko 	    * MFI_SECTOR_LEN;
8710d9a4ef3SDoug Ambrisko }
8720d9a4ef3SDoug Ambrisko 
87352d5baa2SDoug Ambrisko int
mfi_tbolt_build_io(struct mfi_softc * sc,struct mfi_command * mfi_cmd,struct mfi_cmd_tbolt * cmd)87452d5baa2SDoug Ambrisko mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
87552d5baa2SDoug Ambrisko     struct mfi_cmd_tbolt *cmd)
8760d9a4ef3SDoug Ambrisko {
87758ef3154SDoug Ambrisko 	struct mfi_mpi2_request_raid_scsi_io *io_request;
8780d9a4ef3SDoug Ambrisko 	uint32_t sge_count;
87958ef3154SDoug Ambrisko 	uint8_t cdb_len;
88058ef3154SDoug Ambrisko 	int readop;
88158ef3154SDoug Ambrisko 	u_int64_t lba;
8820d9a4ef3SDoug Ambrisko 
88358ef3154SDoug Ambrisko 	io_request = cmd->io_request;
88458ef3154SDoug Ambrisko 	if (!(mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_READ
88558ef3154SDoug Ambrisko 	      || mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE))
8860d9a4ef3SDoug Ambrisko 		return 1;
8870d9a4ef3SDoug Ambrisko 
88858ef3154SDoug Ambrisko 	mfi_tbolt_build_ldio(sc, mfi_cmd, cmd);
88958ef3154SDoug Ambrisko 
89058ef3154SDoug Ambrisko 	/* Convert to SCSI command CDB */
89158ef3154SDoug Ambrisko 	bzero(io_request->CDB.CDB32, sizeof(io_request->CDB.CDB32));
89258ef3154SDoug Ambrisko 	if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
89358ef3154SDoug Ambrisko 		readop = 0;
89458ef3154SDoug Ambrisko 	else
89558ef3154SDoug Ambrisko 		readop = 1;
89658ef3154SDoug Ambrisko 
89758ef3154SDoug Ambrisko 	lba =  mfi_cmd->cm_frame->io.lba_hi;
89858ef3154SDoug Ambrisko 	lba = (lba << 32) + mfi_cmd->cm_frame->io.lba_lo;
89958ef3154SDoug Ambrisko 	cdb_len = mfi_build_cdb(readop, 0, lba,
90058ef3154SDoug Ambrisko 	    mfi_cmd->cm_frame->io.header.data_len, io_request->CDB.CDB32);
90158ef3154SDoug Ambrisko 
9020d9a4ef3SDoug Ambrisko 	/* Just the CDB length, rest of the Flags are zero */
9030d9a4ef3SDoug Ambrisko 	io_request->IoFlags = cdb_len;
9040d9a4ef3SDoug Ambrisko 
9050d9a4ef3SDoug Ambrisko 	/*
9060d9a4ef3SDoug Ambrisko 	 * Construct SGL
9070d9a4ef3SDoug Ambrisko 	 */
9080d9a4ef3SDoug Ambrisko 	sge_count = mfi_tbolt_make_sgl(sc, mfi_cmd,
9090d9a4ef3SDoug Ambrisko 	    (pMpi25IeeeSgeChain64_t) &io_request->SGL, cmd);
9100d9a4ef3SDoug Ambrisko 	if (sge_count > sc->mfi_max_sge) {
9110d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Error. sge_count (0x%x) exceeds "
9120d9a4ef3SDoug Ambrisko 		    "max (0x%x) allowed\n", sge_count, sc->mfi_max_sge);
9130d9a4ef3SDoug Ambrisko 		return 1;
9140d9a4ef3SDoug Ambrisko 	}
9150d9a4ef3SDoug Ambrisko 	io_request->RaidContext.numSGE = sge_count;
9160d9a4ef3SDoug Ambrisko 	io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
9170d9a4ef3SDoug Ambrisko 
9180d9a4ef3SDoug Ambrisko 	if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
9190d9a4ef3SDoug Ambrisko 		io_request->Control = MPI2_SCSIIO_CONTROL_WRITE;
9200d9a4ef3SDoug Ambrisko 	else
9210d9a4ef3SDoug Ambrisko 		io_request->Control = MPI2_SCSIIO_CONTROL_READ;
9220d9a4ef3SDoug Ambrisko 
9230d9a4ef3SDoug Ambrisko 	io_request->SGLOffset0 = offsetof(
9240d9a4ef3SDoug Ambrisko 	    struct mfi_mpi2_request_raid_scsi_io, SGL)/4;
9250d9a4ef3SDoug Ambrisko 
9260d9a4ef3SDoug Ambrisko 	io_request->SenseBufferLowAddress = mfi_cmd->cm_sense_busaddr;
9270d9a4ef3SDoug Ambrisko 	io_request->SenseBufferLength = MFI_SENSE_LEN;
92858ef3154SDoug Ambrisko 	io_request->RaidContext.Status = MFI_STAT_INVALID_STATUS;
92958ef3154SDoug Ambrisko 	io_request->RaidContext.exStatus = MFI_STAT_INVALID_STATUS;
93058ef3154SDoug Ambrisko 
9310d9a4ef3SDoug Ambrisko 	return 0;
9320d9a4ef3SDoug Ambrisko }
9330d9a4ef3SDoug Ambrisko 
9340d9a4ef3SDoug Ambrisko static int
mfi_tbolt_make_sgl(struct mfi_softc * sc,struct mfi_command * mfi_cmd,pMpi25IeeeSgeChain64_t sgl_ptr,struct mfi_cmd_tbolt * cmd)9350d9a4ef3SDoug Ambrisko mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
9360d9a4ef3SDoug Ambrisko 		   pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd)
9370d9a4ef3SDoug Ambrisko {
9386ef1ad0dSScott Long 	uint8_t i, sg_processed;
9390d9a4ef3SDoug Ambrisko 	uint8_t sge_count, sge_idx;
9400d9a4ef3SDoug Ambrisko 	union mfi_sgl *os_sgl;
9413b8ad66eSMark Johnston 	pMpi25IeeeSgeChain64_t sgl_end;
9420d9a4ef3SDoug Ambrisko 
9430d9a4ef3SDoug Ambrisko 	/*
9440d9a4ef3SDoug Ambrisko 	 * Return 0 if there is no data transfer
9450d9a4ef3SDoug Ambrisko 	 */
9460d9a4ef3SDoug Ambrisko 	if (!mfi_cmd->cm_sg || !mfi_cmd->cm_len) {
9470d9a4ef3SDoug Ambrisko 	 	device_printf(sc->mfi_dev, "Buffer empty \n");
9480d9a4ef3SDoug Ambrisko 		return 0;
9490d9a4ef3SDoug Ambrisko 	}
9500d9a4ef3SDoug Ambrisko 	os_sgl = mfi_cmd->cm_sg;
9510d9a4ef3SDoug Ambrisko 	sge_count = mfi_cmd->cm_frame->header.sg_count;
9520d9a4ef3SDoug Ambrisko 
9530d9a4ef3SDoug Ambrisko 	if (sge_count > sc->mfi_max_sge) {
9540d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "sgl ptr %p sg_cnt %d \n",
9550d9a4ef3SDoug Ambrisko 		    os_sgl, sge_count);
9560d9a4ef3SDoug Ambrisko 		return sge_count;
9570d9a4ef3SDoug Ambrisko 	}
9580d9a4ef3SDoug Ambrisko 
9590d9a4ef3SDoug Ambrisko 	if (sge_count > sc->max_SGEs_in_main_message)
9600d9a4ef3SDoug Ambrisko 		/* One element to store the chain info */
9610d9a4ef3SDoug Ambrisko 		sge_idx = sc->max_SGEs_in_main_message - 1;
9620d9a4ef3SDoug Ambrisko 	else
9630d9a4ef3SDoug Ambrisko 		sge_idx = sge_count;
9640d9a4ef3SDoug Ambrisko 
9653b8ad66eSMark Johnston 	if (sc->mfi_flags & (MFI_FLAGS_INVADER | MFI_FLAGS_FURY)) {
9663b8ad66eSMark Johnston 		sgl_end = sgl_ptr + (sc->max_SGEs_in_main_message - 1);
9673b8ad66eSMark Johnston 		sgl_end->Flags = 0;
9683b8ad66eSMark Johnston 	}
9693b8ad66eSMark Johnston 
9700d9a4ef3SDoug Ambrisko 	for (i = 0; i < sge_idx; i++) {
9710d9a4ef3SDoug Ambrisko 		/*
972a6ba0fd6SDoug Ambrisko 		 * For 32bit BSD we are getting 32 bit SGL's from OS
973a6ba0fd6SDoug Ambrisko 		 * but FW only take 64 bit SGL's so copying from 32 bit
974a6ba0fd6SDoug Ambrisko 		 * SGL's to 64.
9750d9a4ef3SDoug Ambrisko 		 */
9760d9a4ef3SDoug Ambrisko 		if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
9770d9a4ef3SDoug Ambrisko 			sgl_ptr->Length = os_sgl->sg_skinny[i].len;
9780d9a4ef3SDoug Ambrisko 			sgl_ptr->Address = os_sgl->sg_skinny[i].addr;
9790d9a4ef3SDoug Ambrisko 		} else {
9800d9a4ef3SDoug Ambrisko 			sgl_ptr->Length = os_sgl->sg32[i].len;
981a6ba0fd6SDoug Ambrisko 			sgl_ptr->Address = os_sgl->sg32[i].addr;
9820d9a4ef3SDoug Ambrisko 		}
9833b8ad66eSMark Johnston 		if (i == sge_count - 1 &&
9843b8ad66eSMark Johnston 		    (sc->mfi_flags & (MFI_FLAGS_INVADER | MFI_FLAGS_FURY)))
9853b8ad66eSMark Johnston 			sgl_ptr->Flags = MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
9863b8ad66eSMark Johnston 		else
9870d9a4ef3SDoug Ambrisko 			sgl_ptr->Flags = 0;
9880d9a4ef3SDoug Ambrisko 		sgl_ptr++;
9890d9a4ef3SDoug Ambrisko 		cmd->io_request->ChainOffset = 0;
9900d9a4ef3SDoug Ambrisko 	}
9910d9a4ef3SDoug Ambrisko 
9920d9a4ef3SDoug Ambrisko 	sg_processed = i;
9930d9a4ef3SDoug Ambrisko 
9940d9a4ef3SDoug Ambrisko 	if (sg_processed < sge_count) {
9950d9a4ef3SDoug Ambrisko 		pMpi25IeeeSgeChain64_t sg_chain;
9966ef1ad0dSScott Long 
9970d9a4ef3SDoug Ambrisko 		cmd->io_request->ChainOffset =
9980d9a4ef3SDoug Ambrisko 		    sc->chain_offset_value_for_main_message;
9990d9a4ef3SDoug Ambrisko 		sg_chain = sgl_ptr;
10000d9a4ef3SDoug Ambrisko 		/* Prepare chain element */
10010d9a4ef3SDoug Ambrisko 		sg_chain->NextChainOffset = 0;
10023b8ad66eSMark Johnston 		if (sc->mfi_flags & (MFI_FLAGS_INVADER | MFI_FLAGS_FURY))
10033b8ad66eSMark Johnston 			sg_chain->Flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT;
10043b8ad66eSMark Johnston 		else
10053b8ad66eSMark Johnston 			sg_chain->Flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
10063b8ad66eSMark Johnston 			    MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
10070d9a4ef3SDoug Ambrisko 		sg_chain->Length =  (sizeof(MPI2_SGE_IO_UNION) *
10080d9a4ef3SDoug Ambrisko 		    (sge_count - sg_processed));
1009a6ba0fd6SDoug Ambrisko 		sg_chain->Address = cmd->sg_frame_phys_addr;
10100d9a4ef3SDoug Ambrisko 		sgl_ptr = (pMpi25IeeeSgeChain64_t)cmd->sg_frame;
10110d9a4ef3SDoug Ambrisko 		for (; i < sge_count; i++) {
10120d9a4ef3SDoug Ambrisko 			if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
10130d9a4ef3SDoug Ambrisko 				sgl_ptr->Length = os_sgl->sg_skinny[i].len;
10140d9a4ef3SDoug Ambrisko 				sgl_ptr->Address = os_sgl->sg_skinny[i].addr;
1015a6ba0fd6SDoug Ambrisko 			} else {
10160d9a4ef3SDoug Ambrisko 				sgl_ptr->Length = os_sgl->sg32[i].len;
1017a6ba0fd6SDoug Ambrisko 				sgl_ptr->Address = os_sgl->sg32[i].addr;
10180d9a4ef3SDoug Ambrisko 			}
10193b8ad66eSMark Johnston 			if (i == sge_count - 1 &&
10203b8ad66eSMark Johnston 			    (sc->mfi_flags &
10213b8ad66eSMark Johnston 			    (MFI_FLAGS_INVADER | MFI_FLAGS_FURY)))
10223b8ad66eSMark Johnston 				sgl_ptr->Flags =
10233b8ad66eSMark Johnston 				    MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
10243b8ad66eSMark Johnston 			else
10250d9a4ef3SDoug Ambrisko 				sgl_ptr->Flags = 0;
10260d9a4ef3SDoug Ambrisko 			sgl_ptr++;
10270d9a4ef3SDoug Ambrisko 		}
10280d9a4ef3SDoug Ambrisko 	}
10290d9a4ef3SDoug Ambrisko 	return sge_count;
10300d9a4ef3SDoug Ambrisko }
10310d9a4ef3SDoug Ambrisko 
10320d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *
mfi_build_and_issue_cmd(struct mfi_softc * sc,struct mfi_command * mfi_cmd)10330d9a4ef3SDoug Ambrisko mfi_build_and_issue_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd)
10340d9a4ef3SDoug Ambrisko {
10350d9a4ef3SDoug Ambrisko 	struct mfi_cmd_tbolt *cmd;
10360d9a4ef3SDoug Ambrisko 	union mfi_mpi2_request_descriptor *req_desc = NULL;
10370d9a4ef3SDoug Ambrisko 	uint16_t index;
103808c89430SSteven Hartland 	cmd = mfi_tbolt_get_cmd(sc, mfi_cmd);
103908c89430SSteven Hartland 	if (cmd == NULL)
104008c89430SSteven Hartland 		return (NULL);
10410d9a4ef3SDoug Ambrisko 
10420d9a4ef3SDoug Ambrisko 	index = cmd->index;
10430d9a4ef3SDoug Ambrisko 	req_desc = mfi_tbolt_get_request_descriptor(sc, index-1);
104408c89430SSteven Hartland 	if (req_desc == NULL) {
104508c89430SSteven Hartland 		mfi_tbolt_return_cmd(sc, cmd, mfi_cmd);
104608c89430SSteven Hartland 		return (NULL);
104708c89430SSteven Hartland 	}
104808c89430SSteven Hartland 
104908c89430SSteven Hartland 	if (mfi_tbolt_build_io(sc, mfi_cmd, cmd) != 0) {
105008c89430SSteven Hartland 		mfi_tbolt_return_cmd(sc, cmd, mfi_cmd);
105108c89430SSteven Hartland 		return (NULL);
105208c89430SSteven Hartland 	}
10530d9a4ef3SDoug Ambrisko 	req_desc->header.SMID = index;
10540d9a4ef3SDoug Ambrisko 	return req_desc;
10550d9a4ef3SDoug Ambrisko }
10560d9a4ef3SDoug Ambrisko 
10570d9a4ef3SDoug Ambrisko union mfi_mpi2_request_descriptor *
mfi_tbolt_build_mpt_cmd(struct mfi_softc * sc,struct mfi_command * cmd)10580d9a4ef3SDoug Ambrisko mfi_tbolt_build_mpt_cmd(struct mfi_softc *sc, struct mfi_command *cmd)
10590d9a4ef3SDoug Ambrisko {
10600d9a4ef3SDoug Ambrisko 	union mfi_mpi2_request_descriptor *req_desc = NULL;
10610d9a4ef3SDoug Ambrisko 	uint16_t index;
10620d9a4ef3SDoug Ambrisko 	if (mfi_build_mpt_pass_thru(sc, cmd)) {
10630d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Couldn't build MFI pass thru "
10640d9a4ef3SDoug Ambrisko 		    "cmd\n");
10650d9a4ef3SDoug Ambrisko 		return NULL;
10660d9a4ef3SDoug Ambrisko 	}
10670d9a4ef3SDoug Ambrisko 	/* For fusion the frame_count variable is used for SMID */
10680d9a4ef3SDoug Ambrisko 	index = cmd->cm_extra_frames;
10690d9a4ef3SDoug Ambrisko 
10700d9a4ef3SDoug Ambrisko 	req_desc = mfi_tbolt_get_request_descriptor(sc, index - 1);
107108c89430SSteven Hartland 	if (req_desc == NULL)
10720d9a4ef3SDoug Ambrisko 		return NULL;
10730d9a4ef3SDoug Ambrisko 
1074c61325d0SKevin Lo 	bzero(req_desc, sizeof(*req_desc));
10750d9a4ef3SDoug Ambrisko 	req_desc->header.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
10760d9a4ef3SDoug Ambrisko 	    MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
10770d9a4ef3SDoug Ambrisko 	req_desc->header.SMID = index;
10780d9a4ef3SDoug Ambrisko 	return req_desc;
10790d9a4ef3SDoug Ambrisko }
10800d9a4ef3SDoug Ambrisko 
10810d9a4ef3SDoug Ambrisko int
mfi_tbolt_send_frame(struct mfi_softc * sc,struct mfi_command * cm)10820d9a4ef3SDoug Ambrisko mfi_tbolt_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
10830d9a4ef3SDoug Ambrisko {
10840d9a4ef3SDoug Ambrisko 	struct mfi_frame_header *hdr;
10850d9a4ef3SDoug Ambrisko 	union mfi_mpi2_request_descriptor *req_desc = NULL;
108608c89430SSteven Hartland 	int tm = mfi_polled_cmd_timeout * 1000;
10870d9a4ef3SDoug Ambrisko 
10880d9a4ef3SDoug Ambrisko 	hdr = &cm->cm_frame->header;
10890d9a4ef3SDoug Ambrisko 	if (sc->adpreset)
10900d9a4ef3SDoug Ambrisko 		return 1;
10910d9a4ef3SDoug Ambrisko 	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
10920d9a4ef3SDoug Ambrisko 		cm->cm_timestamp = time_uptime;
10930d9a4ef3SDoug Ambrisko 		mfi_enqueue_busy(cm);
109458ef3154SDoug Ambrisko 	} else {	/* still get interrupts for it */
1095ddbffe7fSDoug Ambrisko 		hdr->cmd_status = MFI_STAT_INVALID_STATUS;
10960d9a4ef3SDoug Ambrisko 		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
10970d9a4ef3SDoug Ambrisko 	}
10980d9a4ef3SDoug Ambrisko 
10990d9a4ef3SDoug Ambrisko 	if (hdr->cmd == MFI_CMD_PD_SCSI_IO) {
11000d9a4ef3SDoug Ambrisko 		/* check for inquiry commands coming from CLI */
11010d9a4ef3SDoug Ambrisko 		if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) ==
11020d9a4ef3SDoug Ambrisko 		    NULL) {
11030d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "Mapping from MFI "
11040d9a4ef3SDoug Ambrisko 			    "to MPT Failed \n");
11050d9a4ef3SDoug Ambrisko 			return 1;
11060d9a4ef3SDoug Ambrisko 		}
110758ef3154SDoug Ambrisko 	} else if (hdr->cmd == MFI_CMD_LD_SCSI_IO ||
11080d9a4ef3SDoug Ambrisko 	    hdr->cmd == MFI_CMD_LD_READ || hdr->cmd == MFI_CMD_LD_WRITE) {
110958ef3154SDoug Ambrisko 		cm->cm_flags |= MFI_CMD_SCSI;
11100d9a4ef3SDoug Ambrisko 		if ((req_desc = mfi_build_and_issue_cmd(sc, cm)) == NULL) {
11110d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "LDIO Failed \n");
11120d9a4ef3SDoug Ambrisko 			return 1;
11130d9a4ef3SDoug Ambrisko 		}
111458ef3154SDoug Ambrisko 	} else if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == NULL) {
111508c89430SSteven Hartland 		device_printf(sc->mfi_dev, "Mapping from MFI to MPT Failed\n");
111608c89430SSteven Hartland 		return (1);
11170d9a4ef3SDoug Ambrisko 	}
111858ef3154SDoug Ambrisko 
111958ef3154SDoug Ambrisko 	if (cm->cm_flags & MFI_CMD_SCSI) {
112058ef3154SDoug Ambrisko 		/*
112158ef3154SDoug Ambrisko 		 * LD IO needs to be posted since it doesn't get
112258ef3154SDoug Ambrisko 		 * acknowledged via a status update so have the
112358ef3154SDoug Ambrisko 		 * controller reply via mfi_tbolt_complete_cmd.
112458ef3154SDoug Ambrisko 		 */
112558ef3154SDoug Ambrisko 		hdr->flags &= ~MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
112658ef3154SDoug Ambrisko 	}
112758ef3154SDoug Ambrisko 
11280d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_ILQP, (req_desc->words & 0xFFFFFFFF));
11290d9a4ef3SDoug Ambrisko 	MFI_WRITE4(sc, MFI_IHQP, (req_desc->words >>0x20));
11300d9a4ef3SDoug Ambrisko 
11310d9a4ef3SDoug Ambrisko 	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
11320d9a4ef3SDoug Ambrisko 		return 0;
11330d9a4ef3SDoug Ambrisko 
113408c89430SSteven Hartland 	/*
113508c89430SSteven Hartland 	 * This is a polled command, so busy-wait for it to complete.
113608c89430SSteven Hartland 	 *
113708c89430SSteven Hartland 	 * The value of hdr->cmd_status is updated directly by the hardware
1138453130d9SPedro F. Giffuni 	 * so there is no guarantee that mfi_tbolt_complete_cmd is called
113908c89430SSteven Hartland 	 * prior to this value changing.
114008c89430SSteven Hartland 	 */
1141ddbffe7fSDoug Ambrisko 	while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
11420d9a4ef3SDoug Ambrisko 		DELAY(1000);
11430d9a4ef3SDoug Ambrisko 		tm -= 1;
11440d9a4ef3SDoug Ambrisko 		if (tm <= 0)
11450d9a4ef3SDoug Ambrisko 			break;
114658ef3154SDoug Ambrisko 		if (cm->cm_flags & MFI_CMD_SCSI) {
114708c89430SSteven Hartland 			/*
114808c89430SSteven Hartland 			 * Force check reply queue.
114908c89430SSteven Hartland 			 * This ensures that dump works correctly
115008c89430SSteven Hartland 			 */
115158ef3154SDoug Ambrisko 			mfi_tbolt_complete_cmd(sc);
115258ef3154SDoug Ambrisko 		}
11530d9a4ef3SDoug Ambrisko 	}
11540d9a4ef3SDoug Ambrisko 
115508c89430SSteven Hartland 	/* ensure the command cleanup has been processed before returning */
115608c89430SSteven Hartland 	mfi_tbolt_complete_cmd(sc);
115708c89430SSteven Hartland 
1158ddbffe7fSDoug Ambrisko 	if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
11590d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Frame %p timed out "
11600d9a4ef3SDoug Ambrisko 		    "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
11610d9a4ef3SDoug Ambrisko 		return (ETIMEDOUT);
11620d9a4ef3SDoug Ambrisko 	}
11630d9a4ef3SDoug Ambrisko 	return 0;
11640d9a4ef3SDoug Ambrisko }
11650d9a4ef3SDoug Ambrisko 
116652d5baa2SDoug Ambrisko static void
mfi_issue_pending_cmds_again(struct mfi_softc * sc)116752d5baa2SDoug Ambrisko mfi_issue_pending_cmds_again(struct mfi_softc *sc)
11680d9a4ef3SDoug Ambrisko {
11690d9a4ef3SDoug Ambrisko 	struct mfi_command *cm, *tmp;
117008c89430SSteven Hartland 	struct mfi_cmd_tbolt *cmd;
11710d9a4ef3SDoug Ambrisko 
11720d9a4ef3SDoug Ambrisko 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
11730d9a4ef3SDoug Ambrisko 	TAILQ_FOREACH_REVERSE_SAFE(cm, &sc->mfi_busy, BUSYQ, cm_link, tmp) {
11740d9a4ef3SDoug Ambrisko 		cm->retry_for_fw_reset++;
11750d9a4ef3SDoug Ambrisko 
11760d9a4ef3SDoug Ambrisko 		/*
11770d9a4ef3SDoug Ambrisko 		 * If a command has continuously been tried multiple times
11780d9a4ef3SDoug Ambrisko 		 * and causing a FW reset condition, no further recoveries
11790d9a4ef3SDoug Ambrisko 		 * should be performed on the controller
11800d9a4ef3SDoug Ambrisko 		 */
11810d9a4ef3SDoug Ambrisko 		if (cm->retry_for_fw_reset == 3) {
118208c89430SSteven Hartland 			device_printf(sc->mfi_dev, "megaraid_sas: command %p "
118308c89430SSteven Hartland 			    "index=%d was tried multiple times during adapter "
118408c89430SSteven Hartland 			    "reset - Shutting down the HBA\n", cm, cm->cm_index);
11850d9a4ef3SDoug Ambrisko 			mfi_kill_hba(sc);
11860d9a4ef3SDoug Ambrisko 			sc->hw_crit_error = 1;
11870d9a4ef3SDoug Ambrisko 			return;
11880d9a4ef3SDoug Ambrisko 		}
11890d9a4ef3SDoug Ambrisko 
11900d9a4ef3SDoug Ambrisko 		mfi_remove_busy(cm);
119108c89430SSteven Hartland 		if ((cm->cm_flags & MFI_CMD_TBOLT) != 0) {
119208c89430SSteven Hartland 			if (cm->cm_extra_frames != 0 && cm->cm_extra_frames <=
119308c89430SSteven Hartland 			    sc->mfi_max_fw_cmds) {
119408c89430SSteven Hartland 				cmd = sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames - 1];
119508c89430SSteven Hartland 				mfi_tbolt_return_cmd(sc, cmd, cm);
119608c89430SSteven Hartland 			} else {
11970d9a4ef3SDoug Ambrisko 				device_printf(sc->mfi_dev,
119808c89430SSteven Hartland 				    "Invalid extra_frames: %d detected\n",
119908c89430SSteven Hartland 				    cm->cm_extra_frames);
120008c89430SSteven Hartland 			}
120108c89430SSteven Hartland 		}
120208c89430SSteven Hartland 
120308c89430SSteven Hartland 		if (cm->cm_frame->dcmd.opcode != MFI_DCMD_CTRL_EVENT_WAIT) {
120408c89430SSteven Hartland 			device_printf(sc->mfi_dev,
120508c89430SSteven Hartland 			    "APJ ****requeue command %p index=%d\n",
120608c89430SSteven Hartland 			    cm, cm->cm_index);
12070d9a4ef3SDoug Ambrisko 			mfi_requeue_ready(cm);
120808c89430SSteven Hartland 		} else
12090d9a4ef3SDoug Ambrisko 			mfi_release_command(cm);
12100d9a4ef3SDoug Ambrisko 	}
12110d9a4ef3SDoug Ambrisko 	mfi_startio(sc);
12120d9a4ef3SDoug Ambrisko }
12130d9a4ef3SDoug Ambrisko 
121452d5baa2SDoug Ambrisko static void
mfi_kill_hba(struct mfi_softc * sc)121552d5baa2SDoug Ambrisko mfi_kill_hba(struct mfi_softc *sc)
12160d9a4ef3SDoug Ambrisko {
12170d9a4ef3SDoug Ambrisko 	if (sc->mfi_flags & MFI_FLAGS_TBOLT)
12180d9a4ef3SDoug Ambrisko 		MFI_WRITE4(sc, 0x00, MFI_STOP_ADP);
12190d9a4ef3SDoug Ambrisko 	else
12200d9a4ef3SDoug Ambrisko 		MFI_WRITE4(sc, MFI_IDB, MFI_STOP_ADP);
12210d9a4ef3SDoug Ambrisko }
12220d9a4ef3SDoug Ambrisko 
122352d5baa2SDoug Ambrisko static void
mfi_process_fw_state_chg_isr(void * arg)122452d5baa2SDoug Ambrisko mfi_process_fw_state_chg_isr(void *arg)
12250d9a4ef3SDoug Ambrisko {
12260d9a4ef3SDoug Ambrisko 	struct mfi_softc *sc= (struct mfi_softc *)arg;
12270d9a4ef3SDoug Ambrisko 	int error, status;
12280d9a4ef3SDoug Ambrisko 
12290d9a4ef3SDoug Ambrisko 	if (sc->adpreset == 1) {
12300d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "First stage of FW reset "
12310d9a4ef3SDoug Ambrisko 		     "initiated...\n");
12320d9a4ef3SDoug Ambrisko 
12330d9a4ef3SDoug Ambrisko 		sc->mfi_adp_reset(sc);
12340d9a4ef3SDoug Ambrisko 		sc->mfi_enable_intr(sc);
12350d9a4ef3SDoug Ambrisko 
12360d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "First stage of reset complete, "
12370d9a4ef3SDoug Ambrisko 		    "second stage initiated...\n");
12380d9a4ef3SDoug Ambrisko 
12390d9a4ef3SDoug Ambrisko 		sc->adpreset = 2;
12400d9a4ef3SDoug Ambrisko 
12410d9a4ef3SDoug Ambrisko 		/* waiting for about 20 second before start the second init */
12420d9a4ef3SDoug Ambrisko 		for (int wait = 0; wait < 20000; wait++)
12430d9a4ef3SDoug Ambrisko 			DELAY(1000);
12440d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "Second stage of FW reset "
12450d9a4ef3SDoug Ambrisko 		     "initiated...\n");
12460d9a4ef3SDoug Ambrisko 		while ((status = MFI_READ4(sc, MFI_RSR)) & 0x04);
12470d9a4ef3SDoug Ambrisko 
12480d9a4ef3SDoug Ambrisko 		sc->mfi_disable_intr(sc);
12490d9a4ef3SDoug Ambrisko 
12500d9a4ef3SDoug Ambrisko 		/* We expect the FW state to be READY */
12510d9a4ef3SDoug Ambrisko 		if (mfi_transition_firmware(sc)) {
1252a6ba0fd6SDoug Ambrisko 			device_printf(sc->mfi_dev, "controller is not in "
1253a6ba0fd6SDoug Ambrisko 			    "ready state\n");
12540d9a4ef3SDoug Ambrisko 			mfi_kill_hba(sc);
12550d9a4ef3SDoug Ambrisko 			sc->hw_crit_error = 1;
12560d9a4ef3SDoug Ambrisko 			return;
12570d9a4ef3SDoug Ambrisko 		}
125808c89430SSteven Hartland 		if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) {
125908c89430SSteven Hartland 			device_printf(sc->mfi_dev, "Failed to initialise MFI "
126008c89430SSteven Hartland 			    "queue\n");
126108c89430SSteven Hartland 			mfi_kill_hba(sc);
126208c89430SSteven Hartland 			sc->hw_crit_error = 1;
12630d9a4ef3SDoug Ambrisko 			return;
126408c89430SSteven Hartland 		}
12650d9a4ef3SDoug Ambrisko 
126608c89430SSteven Hartland 		/* Init last reply index and max */
126708c89430SSteven Hartland 		MFI_WRITE4(sc, MFI_RFPI, sc->mfi_max_fw_cmds - 1);
126808c89430SSteven Hartland 		MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
12690d9a4ef3SDoug Ambrisko 
12700d9a4ef3SDoug Ambrisko 		sc->mfi_enable_intr(sc);
12710d9a4ef3SDoug Ambrisko 		sc->adpreset = 0;
127208c89430SSteven Hartland 		if (sc->mfi_aen_cm != NULL) {
12730d9a4ef3SDoug Ambrisko 			free(sc->mfi_aen_cm->cm_data, M_MFIBUF);
12740d9a4ef3SDoug Ambrisko 			mfi_remove_busy(sc->mfi_aen_cm);
12750d9a4ef3SDoug Ambrisko 			mfi_release_command(sc->mfi_aen_cm);
12760d9a4ef3SDoug Ambrisko 			sc->mfi_aen_cm = NULL;
12770d9a4ef3SDoug Ambrisko 		}
127808c89430SSteven Hartland 
127908c89430SSteven Hartland 		if (sc->mfi_map_sync_cm != NULL) {
128008c89430SSteven Hartland 			mfi_remove_busy(sc->mfi_map_sync_cm);
1281ddbffe7fSDoug Ambrisko 			mfi_release_command(sc->mfi_map_sync_cm);
1282ddbffe7fSDoug Ambrisko 			sc->mfi_map_sync_cm = NULL;
12830d9a4ef3SDoug Ambrisko 		}
12840d9a4ef3SDoug Ambrisko 		mfi_issue_pending_cmds_again(sc);
12850d9a4ef3SDoug Ambrisko 
12860d9a4ef3SDoug Ambrisko 		/*
12870d9a4ef3SDoug Ambrisko 		 * Issue pending command can result in adapter being marked
12880d9a4ef3SDoug Ambrisko 		 * dead because of too many re-tries. Check for that
12890d9a4ef3SDoug Ambrisko 		 * condition before clearing the reset condition on the FW
12900d9a4ef3SDoug Ambrisko 		 */
12910d9a4ef3SDoug Ambrisko 		if (!sc->hw_crit_error) {
12920d9a4ef3SDoug Ambrisko 			/*
129308c89430SSteven Hartland 			 * Initiate AEN (Asynchronous Event Notification) &
129408c89430SSteven Hartland 			 * Sync Map
12950d9a4ef3SDoug Ambrisko 			 */
12960d9a4ef3SDoug Ambrisko 			mfi_aen_setup(sc, sc->last_seq_num);
129708c89430SSteven Hartland 			mfi_tbolt_sync_map_info(sc);
129808c89430SSteven Hartland 
12990d9a4ef3SDoug Ambrisko 			sc->issuepend_done = 1;
13000d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "second stage of reset "
13010d9a4ef3SDoug Ambrisko 			    "complete, FW is ready now.\n");
13020d9a4ef3SDoug Ambrisko 		} else {
13030d9a4ef3SDoug Ambrisko 			device_printf(sc->mfi_dev, "second stage of reset "
13040d9a4ef3SDoug Ambrisko 			     "never completed, hba was marked offline.\n");
13050d9a4ef3SDoug Ambrisko 		}
13060d9a4ef3SDoug Ambrisko 	} else {
13070d9a4ef3SDoug Ambrisko 		device_printf(sc->mfi_dev, "mfi_process_fw_state_chg_isr "
13080d9a4ef3SDoug Ambrisko 		    "called with unhandled value:%d\n", sc->adpreset);
13090d9a4ef3SDoug Ambrisko 	}
13100d9a4ef3SDoug Ambrisko }
1311ddbffe7fSDoug Ambrisko 
1312ddbffe7fSDoug Ambrisko /*
1313ddbffe7fSDoug Ambrisko  * The ThunderBolt HW has an option for the driver to directly
1314ddbffe7fSDoug Ambrisko  * access the underlying disks and operate on the RAID.  To
1315ddbffe7fSDoug Ambrisko  * do this there needs to be a capability to keep the RAID controller
1316ddbffe7fSDoug Ambrisko  * and driver in sync.  The FreeBSD driver does not take advantage
1317ddbffe7fSDoug Ambrisko  * of this feature since it adds a lot of complexity and slows down
1318ddbffe7fSDoug Ambrisko  * performance.  Performance is gained by using the controller's
1319ddbffe7fSDoug Ambrisko  * cache etc.
1320ddbffe7fSDoug Ambrisko  *
1321ddbffe7fSDoug Ambrisko  * Even though this driver doesn't access the disks directly, an
1322ddbffe7fSDoug Ambrisko  * AEN like command is used to inform the RAID firmware to "sync"
1323ddbffe7fSDoug Ambrisko  * with all LD's via the MFI_DCMD_LD_MAP_GET_INFO command.  This
1324ddbffe7fSDoug Ambrisko  * command in write mode will return when the RAID firmware has
1325ddbffe7fSDoug Ambrisko  * detected a change to the RAID state.  Examples of this type
1326ddbffe7fSDoug Ambrisko  * of change are removing a disk.  Once the command returns then
1327ddbffe7fSDoug Ambrisko  * the driver needs to acknowledge this and "sync" all LD's again.
1328ddbffe7fSDoug Ambrisko  * This repeats until we shutdown.  Then we need to cancel this
1329ddbffe7fSDoug Ambrisko  * pending command.
1330ddbffe7fSDoug Ambrisko  *
1331ddbffe7fSDoug Ambrisko  * If this is not done right the RAID firmware will not remove a
1332ddbffe7fSDoug Ambrisko  * pulled drive and the RAID won't go degraded etc.  Effectively,
1333ddbffe7fSDoug Ambrisko  * stopping any RAID mangement to functions.
1334ddbffe7fSDoug Ambrisko  *
1335ddbffe7fSDoug Ambrisko  * Doing another LD sync, requires the use of an event since the
1336ddbffe7fSDoug Ambrisko  * driver needs to do a mfi_wait_command and can't do that in an
1337ddbffe7fSDoug Ambrisko  * interrupt thread.
1338ddbffe7fSDoug Ambrisko  *
1339ddbffe7fSDoug Ambrisko  * The driver could get the RAID state via the MFI_DCMD_LD_MAP_GET_INFO
1340453130d9SPedro F. Giffuni  * That requires a bunch of structure and it is simpler to just do
1341ddbffe7fSDoug Ambrisko  * the MFI_DCMD_LD_GET_LIST versus walking the RAID map.
1342ddbffe7fSDoug Ambrisko  */
1343ddbffe7fSDoug Ambrisko 
1344ddbffe7fSDoug Ambrisko void
mfi_tbolt_sync_map_info(struct mfi_softc * sc)1345ddbffe7fSDoug Ambrisko mfi_tbolt_sync_map_info(struct mfi_softc *sc)
1346ddbffe7fSDoug Ambrisko {
1347ddbffe7fSDoug Ambrisko 	int error = 0, i;
134808c89430SSteven Hartland 	struct mfi_command *cmd = NULL;
134908c89430SSteven Hartland 	struct mfi_dcmd_frame *dcmd = NULL;
1350ddbffe7fSDoug Ambrisko 	uint32_t context = 0;
135108c89430SSteven Hartland 	union mfi_ld_ref *ld_sync = NULL;
1352ddbffe7fSDoug Ambrisko 	size_t ld_size;
1353ddbffe7fSDoug Ambrisko 	struct mfi_frame_header *hdr;
1354ddbffe7fSDoug Ambrisko 	struct mfi_command *cm = NULL;
1355ddbffe7fSDoug Ambrisko 	struct mfi_ld_list *list = NULL;
1356ddbffe7fSDoug Ambrisko 
135708c89430SSteven Hartland 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
135808c89430SSteven Hartland 
1359ddbffe7fSDoug Ambrisko 	if (sc->mfi_map_sync_cm != NULL || sc->cm_map_abort)
1360ddbffe7fSDoug Ambrisko 		return;
1361ddbffe7fSDoug Ambrisko 
1362ddbffe7fSDoug Ambrisko 	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
1363ddbffe7fSDoug Ambrisko 	    (void **)&list, sizeof(*list));
1364ddbffe7fSDoug Ambrisko 	if (error)
1365ddbffe7fSDoug Ambrisko 		goto out;
1366ddbffe7fSDoug Ambrisko 
1367ddbffe7fSDoug Ambrisko 	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAIN;
136808c89430SSteven Hartland 
1369ddbffe7fSDoug Ambrisko 	if (mfi_wait_command(sc, cm) != 0) {
1370ddbffe7fSDoug Ambrisko 		device_printf(sc->mfi_dev, "Failed to get device listing\n");
1371ddbffe7fSDoug Ambrisko 		goto out;
1372ddbffe7fSDoug Ambrisko 	}
1373ddbffe7fSDoug Ambrisko 
1374ddbffe7fSDoug Ambrisko 	hdr = &cm->cm_frame->header;
1375ddbffe7fSDoug Ambrisko 	if (hdr->cmd_status != MFI_STAT_OK) {
1376ddbffe7fSDoug Ambrisko 		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
1377ddbffe7fSDoug Ambrisko 			      hdr->cmd_status);
1378ddbffe7fSDoug Ambrisko 		goto out;
1379ddbffe7fSDoug Ambrisko 	}
1380ddbffe7fSDoug Ambrisko 
1381ddbffe7fSDoug Ambrisko 	ld_size = sizeof(*ld_sync) * list->ld_count;
1382ddbffe7fSDoug Ambrisko 	ld_sync = (union mfi_ld_ref *) malloc(ld_size, M_MFIBUF,
138308c89430SSteven Hartland 	     M_NOWAIT | M_ZERO);
138493fba012SDoug Ambrisko 	if (ld_sync == NULL) {
138593fba012SDoug Ambrisko 		device_printf(sc->mfi_dev, "Failed to allocate sync\n");
138693fba012SDoug Ambrisko 		goto out;
138793fba012SDoug Ambrisko 	}
138808c89430SSteven Hartland 	for (i = 0; i < list->ld_count; i++)
1389ddbffe7fSDoug Ambrisko 		ld_sync[i].ref = list->ld_list[i].ld.ref;
1390ddbffe7fSDoug Ambrisko 
139193fba012SDoug Ambrisko 	if ((cmd = mfi_dequeue_free(sc)) == NULL) {
139293fba012SDoug Ambrisko 		device_printf(sc->mfi_dev, "Failed to get command\n");
139393fba012SDoug Ambrisko 		free(ld_sync, M_MFIBUF);
139493fba012SDoug Ambrisko 		goto out;
139593fba012SDoug Ambrisko 	}
139693fba012SDoug Ambrisko 
1397ddbffe7fSDoug Ambrisko 	context = cmd->cm_frame->header.context;
1398ddbffe7fSDoug Ambrisko 	bzero(cmd->cm_frame, sizeof(union mfi_frame));
1399ddbffe7fSDoug Ambrisko 	cmd->cm_frame->header.context = context;
1400ddbffe7fSDoug Ambrisko 
1401ddbffe7fSDoug Ambrisko 	dcmd = &cmd->cm_frame->dcmd;
1402ddbffe7fSDoug Ambrisko 	bzero(dcmd->mbox, MFI_MBOX_SIZE);
1403ddbffe7fSDoug Ambrisko 	dcmd->header.cmd = MFI_CMD_DCMD;
1404ddbffe7fSDoug Ambrisko 	dcmd->header.flags = MFI_FRAME_DIR_WRITE;
1405ddbffe7fSDoug Ambrisko 	dcmd->header.timeout = 0;
1406ddbffe7fSDoug Ambrisko 	dcmd->header.data_len = ld_size;
1407ddbffe7fSDoug Ambrisko 	dcmd->header.scsi_status = 0;
1408ddbffe7fSDoug Ambrisko 	dcmd->opcode = MFI_DCMD_LD_MAP_GET_INFO;
1409ddbffe7fSDoug Ambrisko 	cmd->cm_sg = &dcmd->sgl;
1410ddbffe7fSDoug Ambrisko 	cmd->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1411ddbffe7fSDoug Ambrisko 	cmd->cm_data = ld_sync;
1412ddbffe7fSDoug Ambrisko 	cmd->cm_private = ld_sync;
1413ddbffe7fSDoug Ambrisko 
1414ddbffe7fSDoug Ambrisko 	cmd->cm_len = ld_size;
1415ddbffe7fSDoug Ambrisko 	cmd->cm_complete = mfi_sync_map_complete;
1416ddbffe7fSDoug Ambrisko 	sc->mfi_map_sync_cm = cmd;
1417ddbffe7fSDoug Ambrisko 
1418ddbffe7fSDoug Ambrisko 	cmd->cm_flags = MFI_CMD_DATAOUT;
1419ddbffe7fSDoug Ambrisko 	cmd->cm_frame->dcmd.mbox[0] = list->ld_count;
1420ddbffe7fSDoug Ambrisko 	cmd->cm_frame->dcmd.mbox[1] = MFI_DCMD_MBOX_PEND_FLAG;
1421ddbffe7fSDoug Ambrisko 
1422ddbffe7fSDoug Ambrisko 	if ((error = mfi_mapcmd(sc, cmd)) != 0) {
1423ddbffe7fSDoug Ambrisko 		device_printf(sc->mfi_dev, "failed to send map sync\n");
142493fba012SDoug Ambrisko 		free(ld_sync, M_MFIBUF);
142593fba012SDoug Ambrisko 		sc->mfi_map_sync_cm = NULL;
142608c89430SSteven Hartland 		mfi_release_command(cmd);
142793fba012SDoug Ambrisko 		goto out;
1428ddbffe7fSDoug Ambrisko 	}
1429ddbffe7fSDoug Ambrisko 
1430ddbffe7fSDoug Ambrisko out:
1431ddbffe7fSDoug Ambrisko 	if (list)
1432ddbffe7fSDoug Ambrisko 		free(list, M_MFIBUF);
1433ddbffe7fSDoug Ambrisko 	if (cm)
1434ddbffe7fSDoug Ambrisko 		mfi_release_command(cm);
1435ddbffe7fSDoug Ambrisko }
1436ddbffe7fSDoug Ambrisko 
1437ddbffe7fSDoug Ambrisko static void
mfi_sync_map_complete(struct mfi_command * cm)1438ddbffe7fSDoug Ambrisko mfi_sync_map_complete(struct mfi_command *cm)
1439ddbffe7fSDoug Ambrisko {
1440ddbffe7fSDoug Ambrisko 	struct mfi_frame_header *hdr;
1441ddbffe7fSDoug Ambrisko 	struct mfi_softc *sc;
1442ddbffe7fSDoug Ambrisko 	int aborted = 0;
1443ddbffe7fSDoug Ambrisko 
1444ddbffe7fSDoug Ambrisko 	sc = cm->cm_sc;
1445ddbffe7fSDoug Ambrisko 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1446ddbffe7fSDoug Ambrisko 
1447ddbffe7fSDoug Ambrisko 	hdr = &cm->cm_frame->header;
1448ddbffe7fSDoug Ambrisko 
1449ddbffe7fSDoug Ambrisko 	if (sc->mfi_map_sync_cm == NULL)
1450ddbffe7fSDoug Ambrisko 		return;
1451ddbffe7fSDoug Ambrisko 
1452ddbffe7fSDoug Ambrisko 	if (sc->cm_map_abort ||
1453ddbffe7fSDoug Ambrisko 	    hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1454ddbffe7fSDoug Ambrisko 		sc->cm_map_abort = 0;
1455ddbffe7fSDoug Ambrisko 		aborted = 1;
1456ddbffe7fSDoug Ambrisko 	}
1457ddbffe7fSDoug Ambrisko 
1458ddbffe7fSDoug Ambrisko 	free(cm->cm_data, M_MFIBUF);
1459ddbffe7fSDoug Ambrisko 	wakeup(&sc->mfi_map_sync_cm);
146008c89430SSteven Hartland 	sc->mfi_map_sync_cm = NULL;
1461ddbffe7fSDoug Ambrisko 	mfi_release_command(cm);
1462ddbffe7fSDoug Ambrisko 
1463ddbffe7fSDoug Ambrisko 	/* set it up again so the driver can catch more events */
146408c89430SSteven Hartland 	if (!aborted)
1465ddbffe7fSDoug Ambrisko 		mfi_queue_map_sync(sc);
1466ddbffe7fSDoug Ambrisko }
1467ddbffe7fSDoug Ambrisko 
1468ddbffe7fSDoug Ambrisko static void
mfi_queue_map_sync(struct mfi_softc * sc)1469ddbffe7fSDoug Ambrisko mfi_queue_map_sync(struct mfi_softc *sc)
1470ddbffe7fSDoug Ambrisko {
1471ddbffe7fSDoug Ambrisko 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1472ddbffe7fSDoug Ambrisko 	taskqueue_enqueue(taskqueue_swi, &sc->mfi_map_sync_task);
1473ddbffe7fSDoug Ambrisko }
1474ddbffe7fSDoug Ambrisko 
1475ddbffe7fSDoug Ambrisko void
mfi_handle_map_sync(void * context,int pending)1476ddbffe7fSDoug Ambrisko mfi_handle_map_sync(void *context, int pending)
1477ddbffe7fSDoug Ambrisko {
1478ddbffe7fSDoug Ambrisko 	struct mfi_softc *sc;
1479ddbffe7fSDoug Ambrisko 
1480ddbffe7fSDoug Ambrisko 	sc = context;
148108c89430SSteven Hartland 	mtx_lock(&sc->mfi_io_lock);
1482ddbffe7fSDoug Ambrisko 	mfi_tbolt_sync_map_info(sc);
148308c89430SSteven Hartland 	mtx_unlock(&sc->mfi_io_lock);
1484ddbffe7fSDoug Ambrisko }
1485