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