xref: /dragonfly/sys/dev/raid/mfi/mfi_tbolt.c (revision 43926ee4)
1590ba11dSSascha Wildner /*-
2590ba11dSSascha Wildner  * Redistribution and use in source and binary forms, with or without
3590ba11dSSascha Wildner  * modification, are permitted provided that the following conditions
4590ba11dSSascha Wildner  * are met:
5590ba11dSSascha Wildner  *
6590ba11dSSascha Wildner  *            Copyright 1994-2009 The FreeBSD Project.
7590ba11dSSascha Wildner  *            All rights reserved.
8590ba11dSSascha Wildner  *
9590ba11dSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
10590ba11dSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
11590ba11dSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
12590ba11dSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
13590ba11dSSascha Wildner  *    documentation and/or other materials provided with the distribution.
14590ba11dSSascha Wildner  *
15590ba11dSSascha Wildner  *    THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND
16590ba11dSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17590ba11dSSascha Wildner  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18590ba11dSSascha Wildner  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FREEBSD PROJECT OR
19590ba11dSSascha Wildner  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20590ba11dSSascha Wildner  * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21590ba11dSSascha Wildner  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22590ba11dSSascha Wildner  * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY
23590ba11dSSascha Wildner  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24590ba11dSSascha Wildner  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25590ba11dSSascha Wildner  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26590ba11dSSascha Wildner  *
27590ba11dSSascha Wildner  * The views and conclusions contained in the software and documentation
28590ba11dSSascha Wildner  * are those of the authors and should not be interpreted as representing
29590ba11dSSascha Wildner  * official policies,either expressed or implied, of the FreeBSD Project.
30590ba11dSSascha Wildner  *
31590ba11dSSascha Wildner  * $FreeBSD: src/sys/dev/mfi/mfi_tbolt.c,v 1.00 2010/06/30 16:00:00 Bharat Gusain Exp $
32590ba11dSSascha Wildner  * FreeBSD projects/head_mfi/ r232949
33590ba11dSSascha Wildner  */
34590ba11dSSascha Wildner 
35590ba11dSSascha Wildner #include "opt_mfi.h"
36590ba11dSSascha Wildner 
37590ba11dSSascha Wildner #include <sys/param.h>
38590ba11dSSascha Wildner #include <sys/types.h>
39590ba11dSSascha Wildner #include <sys/kernel.h>
40590ba11dSSascha Wildner #include <sys/bus.h>
41590ba11dSSascha Wildner #include <sys/conf.h>
42590ba11dSSascha Wildner #include <sys/bio.h>
43590ba11dSSascha Wildner #include <sys/buf2.h>
44590ba11dSSascha Wildner #include <sys/eventhandler.h>
45590ba11dSSascha Wildner #include <sys/callout.h>
46590ba11dSSascha Wildner #include <sys/uio.h>
47590ba11dSSascha Wildner #include <sys/sysctl.h>
48590ba11dSSascha Wildner #include <sys/systm.h>
49590ba11dSSascha Wildner #include <sys/malloc.h>
50590ba11dSSascha Wildner 
51590ba11dSSascha Wildner #include <dev/raid/mfi/mfireg.h>
52590ba11dSSascha Wildner #include <dev/raid/mfi/mfi_ioctl.h>
53590ba11dSSascha Wildner #include <dev/raid/mfi/mfivar.h>
54590ba11dSSascha Wildner 
55590ba11dSSascha Wildner struct mfi_cmd_tbolt *mfi_tbolt_get_cmd(struct mfi_softc *sc);
56590ba11dSSascha Wildner union mfi_mpi2_request_descriptor *
57590ba11dSSascha Wildner mfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index);
58590ba11dSSascha Wildner void mfi_tbolt_complete_cmd(struct mfi_softc *sc);
59590ba11dSSascha Wildner int mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
60590ba11dSSascha Wildner     struct mfi_cmd_tbolt *cmd);
61590ba11dSSascha Wildner static inline void mfi_tbolt_return_cmd(struct mfi_softc *sc,
62590ba11dSSascha Wildner     struct mfi_cmd_tbolt *cmd);
63590ba11dSSascha Wildner union mfi_mpi2_request_descriptor *mfi_tbolt_build_mpt_cmd(struct mfi_softc
64590ba11dSSascha Wildner     *sc, struct mfi_command *cmd);
65590ba11dSSascha Wildner uint8_t
66590ba11dSSascha Wildner mfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd);
67590ba11dSSascha Wildner union mfi_mpi2_request_descriptor *mfi_build_and_issue_cmd(struct mfi_softc
68590ba11dSSascha Wildner     *sc, struct mfi_command *mfi_cmd);
69590ba11dSSascha Wildner int mfi_tbolt_is_ldio(struct mfi_command *mfi_cmd);
70590ba11dSSascha Wildner void mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
71590ba11dSSascha Wildner     struct mfi_cmd_tbolt *cmd);
72590ba11dSSascha Wildner static int mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command
73590ba11dSSascha Wildner     *mfi_cmd, pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd);
74590ba11dSSascha Wildner static int mfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command
75590ba11dSSascha Wildner     *mfi_cmd, uint8_t *cdb);
76590ba11dSSascha Wildner void
77590ba11dSSascha Wildner map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status,
78590ba11dSSascha Wildner      uint8_t ext_status);
79590ba11dSSascha Wildner static void mfi_issue_pending_cmds_again (struct mfi_softc *sc);
80590ba11dSSascha Wildner static void mfi_kill_hba (struct mfi_softc *sc);
81590ba11dSSascha Wildner static void mfi_process_fw_state_chg_isr(void *arg);
82590ba11dSSascha Wildner uint8_t mfi_tbolt_get_map_info(struct mfi_softc *sc);
83590ba11dSSascha Wildner 
84590ba11dSSascha Wildner #define MFI_FUSION_ENABLE_INTERRUPT_MASK	(0x00000008)
85590ba11dSSascha Wildner 
86590ba11dSSascha Wildner void
mfi_tbolt_enable_intr_ppc(struct mfi_softc * sc)87590ba11dSSascha Wildner mfi_tbolt_enable_intr_ppc(struct mfi_softc *sc)
88590ba11dSSascha Wildner {
89590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_OMSK, ~MFI_FUSION_ENABLE_INTERRUPT_MASK);
90590ba11dSSascha Wildner 	MFI_READ4(sc, MFI_OMSK);
91590ba11dSSascha Wildner }
92590ba11dSSascha Wildner 
93590ba11dSSascha Wildner void
mfi_tbolt_disable_intr_ppc(struct mfi_softc * sc)94590ba11dSSascha Wildner mfi_tbolt_disable_intr_ppc(struct mfi_softc *sc)
95590ba11dSSascha Wildner {
96590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_OMSK, 0xFFFFFFFF);
97590ba11dSSascha Wildner 	MFI_READ4(sc, MFI_OMSK);
98590ba11dSSascha Wildner }
99590ba11dSSascha Wildner 
100590ba11dSSascha Wildner int32_t
mfi_tbolt_read_fw_status_ppc(struct mfi_softc * sc)101590ba11dSSascha Wildner mfi_tbolt_read_fw_status_ppc(struct mfi_softc *sc)
102590ba11dSSascha Wildner {
103590ba11dSSascha Wildner 	return MFI_READ4(sc, MFI_OSP0);
104590ba11dSSascha Wildner }
105590ba11dSSascha Wildner 
106590ba11dSSascha Wildner int32_t
mfi_tbolt_check_clear_intr_ppc(struct mfi_softc * sc)107590ba11dSSascha Wildner mfi_tbolt_check_clear_intr_ppc(struct mfi_softc *sc)
108590ba11dSSascha Wildner {
109590ba11dSSascha Wildner 	int32_t status, mfi_status = 0;
110590ba11dSSascha Wildner 
111590ba11dSSascha Wildner 	status = MFI_READ4(sc, MFI_OSTS);
112590ba11dSSascha Wildner 
113590ba11dSSascha Wildner 	if (status & 1) {
114590ba11dSSascha Wildner 		MFI_WRITE4(sc, MFI_OSTS, status);
115590ba11dSSascha Wildner 		MFI_READ4(sc, MFI_OSTS);
116590ba11dSSascha Wildner 		if (status & MFI_STATE_CHANGE_INTERRUPT) {
117590ba11dSSascha Wildner 			mfi_status |= MFI_FIRMWARE_STATE_CHANGE;
118590ba11dSSascha Wildner 		}
119590ba11dSSascha Wildner 
120590ba11dSSascha Wildner 		return mfi_status;
121590ba11dSSascha Wildner 	}
122590ba11dSSascha Wildner 	if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
123590ba11dSSascha Wildner 		return 1;
124590ba11dSSascha Wildner 
125590ba11dSSascha Wildner 	MFI_READ4(sc, MFI_OSTS);
126590ba11dSSascha Wildner 	return 0;
127590ba11dSSascha Wildner }
128590ba11dSSascha Wildner 
129590ba11dSSascha Wildner 
130590ba11dSSascha Wildner void
mfi_tbolt_issue_cmd_ppc(struct mfi_softc * sc,bus_addr_t bus_add,uint32_t frame_cnt)131590ba11dSSascha Wildner mfi_tbolt_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add,
132590ba11dSSascha Wildner    uint32_t frame_cnt)
133590ba11dSSascha Wildner {
134590ba11dSSascha Wildner 	bus_add |= (MFI_REQ_DESCRIPT_FLAGS_MFA
135590ba11dSSascha Wildner 	    << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
136590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_IQPL, (uint32_t)bus_add);
137590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_IQPH, (uint32_t)((uint64_t)bus_add >> 32));
138590ba11dSSascha Wildner }
139590ba11dSSascha Wildner 
140590ba11dSSascha Wildner /**
141590ba11dSSascha Wildner  * mfi_tbolt_adp_reset - For controller reset
142590ba11dSSascha Wildner  * @regs: MFI register set
143590ba11dSSascha Wildner  */
mfi_tbolt_adp_reset(struct mfi_softc * sc)144590ba11dSSascha Wildner int mfi_tbolt_adp_reset(struct mfi_softc *sc)
145590ba11dSSascha Wildner {
146590ba11dSSascha Wildner 	int retry = 0, i = 0;
147590ba11dSSascha Wildner 	int HostDiag;
148590ba11dSSascha Wildner 
149590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_WSR, 0xF);
150590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_WSR, 4);
151590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_WSR, 0xB);
152590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_WSR, 2);
153590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_WSR, 7);
154590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_WSR, 0xD);
155590ba11dSSascha Wildner 
156590ba11dSSascha Wildner 	for (i = 0; i < 10000; i++) ;
157590ba11dSSascha Wildner 
158590ba11dSSascha Wildner 	HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR);
159590ba11dSSascha Wildner 
160590ba11dSSascha Wildner 	while (!( HostDiag & DIAG_WRITE_ENABLE)) {
161590ba11dSSascha Wildner 		for (i = 0; i < 1000; i++);
162590ba11dSSascha Wildner 		HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR);
163590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%x, "
164590ba11dSSascha Wildner 		    "hostdiag=%x\n", retry, HostDiag);
165590ba11dSSascha Wildner 
166590ba11dSSascha Wildner 		if (retry++ >= 100)
167590ba11dSSascha Wildner 			return 1;
168590ba11dSSascha Wildner 	}
169590ba11dSSascha Wildner 
170590ba11dSSascha Wildner 	device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: HostDiag=%x\n", HostDiag);
171590ba11dSSascha Wildner 
172590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_HDR, (HostDiag | DIAG_RESET_ADAPTER));
173590ba11dSSascha Wildner 
174590ba11dSSascha Wildner 	for (i=0; i < 10; i++) {
175590ba11dSSascha Wildner 		for (i = 0; i < 10000; i++);
176590ba11dSSascha Wildner 	}
177590ba11dSSascha Wildner 
178590ba11dSSascha Wildner 	HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR);
179590ba11dSSascha Wildner 	while (HostDiag & DIAG_RESET_ADAPTER) {
180590ba11dSSascha Wildner 		for (i = 0; i < 1000; i++) ;
181590ba11dSSascha Wildner 		HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR);
182590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%x, "
183590ba11dSSascha Wildner 		    "hostdiag=%x\n", retry, HostDiag);
184590ba11dSSascha Wildner 
185590ba11dSSascha Wildner 		if (retry++ >= 1000)
186590ba11dSSascha Wildner 			return 1;
187590ba11dSSascha Wildner 	}
188590ba11dSSascha Wildner 	return 0;
189590ba11dSSascha Wildner }
190590ba11dSSascha Wildner 
191590ba11dSSascha Wildner /*
192590ba11dSSascha Wildner  *******************************************************************************************
193590ba11dSSascha Wildner  * Description:
194590ba11dSSascha Wildner  *      This routine initialize Thunderbolt specific device information
195590ba11dSSascha Wildner  *******************************************************************************************
196590ba11dSSascha Wildner  */
mfi_tbolt_init_globals(struct mfi_softc * sc)197590ba11dSSascha Wildner void mfi_tbolt_init_globals(struct mfi_softc *sc)
198590ba11dSSascha Wildner {
199590ba11dSSascha Wildner 	/* Initialize single reply size and Message size */
200590ba11dSSascha Wildner 	sc->reply_size = MEGASAS_THUNDERBOLT_REPLY_SIZE;
201590ba11dSSascha Wildner 	sc->raid_io_msg_size = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
202590ba11dSSascha Wildner 
203590ba11dSSascha Wildner 	/*
204590ba11dSSascha Wildner 	 * Calculating how many SGEs allowed in a allocated main message
205590ba11dSSascha Wildner 	 * (size of the Message - Raid SCSI IO message size(except SGE))
206590ba11dSSascha Wildner 	 * / size of SGE
207590ba11dSSascha Wildner 	 * (0x100 - (0x90 - 0x10)) / 0x10 = 8
208590ba11dSSascha Wildner 	 */
209590ba11dSSascha Wildner 	sc->max_SGEs_in_main_message =
210590ba11dSSascha Wildner 	    (uint8_t)((sc->raid_io_msg_size
211590ba11dSSascha Wildner 	    - (sizeof(struct mfi_mpi2_request_raid_scsi_io)
212590ba11dSSascha Wildner 	    - sizeof(MPI2_SGE_IO_UNION))) / sizeof(MPI2_SGE_IO_UNION));
213590ba11dSSascha Wildner 	/*
214590ba11dSSascha Wildner 	 * (Command frame size allocaed in SRB ext - Raid SCSI IO message size)
215590ba11dSSascha Wildner 	 * / size of SGL ;
216590ba11dSSascha Wildner 	 * (1280 - 256) / 16 = 64
217590ba11dSSascha Wildner 	 */
218590ba11dSSascha Wildner 	sc->max_SGEs_in_chain_message = (MR_COMMAND_SIZE
219590ba11dSSascha Wildner 	    - sc->raid_io_msg_size) / sizeof(MPI2_SGE_IO_UNION);
220590ba11dSSascha Wildner 	/*
221590ba11dSSascha Wildner 	 * (0x08-1) + 0x40 = 0x47 - 0x01 = 0x46  one is left for command
222590ba11dSSascha Wildner 	 * colscing
223590ba11dSSascha Wildner 	*/
224590ba11dSSascha Wildner 	sc->mfi_max_sge = (sc->max_SGEs_in_main_message - 1)
225590ba11dSSascha Wildner 	    + sc->max_SGEs_in_chain_message - 1;
226590ba11dSSascha Wildner 	/*
227590ba11dSSascha Wildner 	* This is the offset in number of 4 * 32bit words to the next chain
228590ba11dSSascha Wildner 	* (0x100 - 0x10)/0x10 = 0xF(15)
229590ba11dSSascha Wildner 	*/
230590ba11dSSascha Wildner 	sc->chain_offset_value_for_main_message = (sc->raid_io_msg_size
231590ba11dSSascha Wildner 	    - sizeof(MPI2_SGE_IO_UNION))/16;
232590ba11dSSascha Wildner 	sc->chain_offset_value_for_mpt_ptmsg
233590ba11dSSascha Wildner 	    = offsetof(struct mfi_mpi2_request_raid_scsi_io, SGL)/16;
234590ba11dSSascha Wildner 	sc->mfi_cmd_pool_tbolt = NULL;
235590ba11dSSascha Wildner 	sc->request_desc_pool = NULL;
236590ba11dSSascha Wildner }
237590ba11dSSascha Wildner 
238590ba11dSSascha Wildner /*
239590ba11dSSascha Wildner  ****************************************************************************
240590ba11dSSascha Wildner  * Description:
241590ba11dSSascha Wildner  *      This function calculates the memory requirement for Thunderbolt
242590ba11dSSascha Wildner  *      controller
243590ba11dSSascha Wildner  * Return Value:
244590ba11dSSascha Wildner  *      Total required memory in bytes
245590ba11dSSascha Wildner  ****************************************************************************
246590ba11dSSascha Wildner  */
247590ba11dSSascha Wildner 
mfi_tbolt_get_memory_requirement(struct mfi_softc * sc)248590ba11dSSascha Wildner uint32_t mfi_tbolt_get_memory_requirement(struct mfi_softc *sc)
249590ba11dSSascha Wildner {
250590ba11dSSascha Wildner 	uint32_t size;
251590ba11dSSascha Wildner 
252590ba11dSSascha Wildner 	size = MEGASAS_THUNDERBOLT_MSG_ALLIGNMENT;	/* for Alignment */
253590ba11dSSascha Wildner 	size += sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1);
254590ba11dSSascha Wildner 	size += sc->reply_size * sc->mfi_max_fw_cmds;
255590ba11dSSascha Wildner 	/* this is for SGL's */
256590ba11dSSascha Wildner 	size += MEGASAS_MAX_SZ_CHAIN_FRAME * sc->mfi_max_fw_cmds;
257590ba11dSSascha Wildner 	return size;
258590ba11dSSascha Wildner }
259590ba11dSSascha Wildner 
260590ba11dSSascha Wildner /*
261590ba11dSSascha Wildner  ****************************************************************************
262590ba11dSSascha Wildner  * Description:
263590ba11dSSascha Wildner  *      This function will prepare message pools for the Thunderbolt controller
264590ba11dSSascha Wildner  * Arguments:
265590ba11dSSascha Wildner  *      DevExt - HBA miniport driver's adapter data storage structure
266590ba11dSSascha Wildner  *      pMemLocation - start of the memory allocated for Thunderbolt.
267590ba11dSSascha Wildner  * Return Value:
268590ba11dSSascha Wildner  *      TRUE if successful
269590ba11dSSascha Wildner  *      FALSE if failed
270590ba11dSSascha Wildner  ****************************************************************************
271590ba11dSSascha Wildner  */
mfi_tbolt_init_desc_pool(struct mfi_softc * sc,uint8_t * mem_location,uint32_t tbolt_contg_length)272590ba11dSSascha Wildner int mfi_tbolt_init_desc_pool(struct mfi_softc *sc, uint8_t* mem_location,
273590ba11dSSascha Wildner     uint32_t tbolt_contg_length)
274590ba11dSSascha Wildner {
275590ba11dSSascha Wildner 	uint32_t     offset = 0;
276590ba11dSSascha Wildner 	uint8_t      *addr = mem_location;
277590ba11dSSascha Wildner 
278590ba11dSSascha Wildner 	/* Request Descriptor Base physical Address */
279590ba11dSSascha Wildner 
280590ba11dSSascha Wildner 	/* For Request Decriptors Virtual Memory */
281590ba11dSSascha Wildner 	/* Initialise the aligned IO Frames Virtual Memory Pointer */
282590ba11dSSascha Wildner 	if (((uintptr_t)addr) & (0xFF)) {
283590ba11dSSascha Wildner 		addr = &addr[sc->raid_io_msg_size];
284590ba11dSSascha Wildner 		addr = (uint8_t *)((uintptr_t)addr & (~0xFF));
285590ba11dSSascha Wildner 		sc->request_message_pool_align = addr;
286590ba11dSSascha Wildner 	} else
287590ba11dSSascha Wildner 		sc->request_message_pool_align = addr;
288590ba11dSSascha Wildner 
289590ba11dSSascha Wildner 	offset = sc->request_message_pool_align - sc->request_message_pool;
290590ba11dSSascha Wildner 	sc->request_msg_busaddr = sc->mfi_tb_busaddr + offset;
291590ba11dSSascha Wildner 
292590ba11dSSascha Wildner 	/* DJA XXX should this be bus dma ??? */
293590ba11dSSascha Wildner 	/* Skip request message pool */
294590ba11dSSascha Wildner 	addr = &addr[sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1)];
295590ba11dSSascha Wildner 	/* Reply Frame Pool is initialized */
296590ba11dSSascha Wildner 	sc->reply_frame_pool = (struct mfi_mpi2_reply_header *) addr;
297590ba11dSSascha Wildner 	if (((uintptr_t)addr) & (0xFF)) {
298590ba11dSSascha Wildner 		addr = &addr[sc->reply_size];
299590ba11dSSascha Wildner 		addr = (uint8_t *)((uintptr_t)addr & (~0xFF));
300590ba11dSSascha Wildner 	}
301590ba11dSSascha Wildner 	sc->reply_frame_pool_align
302590ba11dSSascha Wildner 		    = (struct mfi_mpi2_reply_header *)addr;
303590ba11dSSascha Wildner 
304590ba11dSSascha Wildner 	offset = (uintptr_t)sc->reply_frame_pool_align
305590ba11dSSascha Wildner 	    - (uintptr_t)sc->request_message_pool;
306590ba11dSSascha Wildner 	sc->reply_frame_busaddr = sc->mfi_tb_busaddr + offset;
307590ba11dSSascha Wildner 
308590ba11dSSascha Wildner 	/* Skip Reply Frame Pool */
309590ba11dSSascha Wildner 	addr += sc->reply_size * sc->mfi_max_fw_cmds;
310590ba11dSSascha Wildner 	sc->reply_pool_limit = addr;
311590ba11dSSascha Wildner 
312590ba11dSSascha Wildner 	/* initializing reply address to 0xFFFFFFFF */
313590ba11dSSascha Wildner 	memset((uint8_t *)sc->reply_frame_pool, 0xFF,
314590ba11dSSascha Wildner 	       (sc->reply_size * sc->mfi_max_fw_cmds));
315590ba11dSSascha Wildner 
316590ba11dSSascha Wildner 	offset = sc->reply_size * sc->mfi_max_fw_cmds;
317590ba11dSSascha Wildner 	sc->sg_frame_busaddr = sc->reply_frame_busaddr + offset;
318590ba11dSSascha Wildner 	/* initialize the last_reply_idx to 0 */
319590ba11dSSascha Wildner 	sc->last_reply_idx = 0;
320590ba11dSSascha Wildner 	offset = (sc->sg_frame_busaddr + (MEGASAS_MAX_SZ_CHAIN_FRAME *
321590ba11dSSascha Wildner 	    sc->mfi_max_fw_cmds)) - sc->mfi_tb_busaddr;
322590ba11dSSascha Wildner 	if (offset > tbolt_contg_length)
323590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "Error:Initialized more than "
324590ba11dSSascha Wildner 		    "allocated\n");
325590ba11dSSascha Wildner 	return 0;
326590ba11dSSascha Wildner }
327590ba11dSSascha Wildner 
328590ba11dSSascha Wildner /*
329590ba11dSSascha Wildner  ****************************************************************************
330590ba11dSSascha Wildner  * Description:
331590ba11dSSascha Wildner  *   This routine prepare and issue INIT2 frame to the Firmware
332590ba11dSSascha Wildner  ****************************************************************************
333590ba11dSSascha Wildner  */
334590ba11dSSascha Wildner 
335590ba11dSSascha Wildner int
mfi_tbolt_init_MFI_queue(struct mfi_softc * sc)336590ba11dSSascha Wildner mfi_tbolt_init_MFI_queue(struct mfi_softc *sc)
337590ba11dSSascha Wildner {
338590ba11dSSascha Wildner 	struct MPI2_IOC_INIT_REQUEST   *mpi2IocInit;
339590ba11dSSascha Wildner 	struct mfi_init_frame	*mfi_init;
340590ba11dSSascha Wildner 	uintptr_t			offset = 0;
341590ba11dSSascha Wildner 	bus_addr_t			phyAddress;
342590ba11dSSascha Wildner 	MFI_ADDRESS			*mfiAddressTemp;
343590ba11dSSascha Wildner 	struct mfi_command *cm;
344590ba11dSSascha Wildner 	int error;
345590ba11dSSascha Wildner 
346590ba11dSSascha Wildner 	mpi2IocInit = (struct MPI2_IOC_INIT_REQUEST *)sc->mfi_tb_ioc_init_desc;
347590ba11dSSascha Wildner 	/* Check if initialization is already completed */
348590ba11dSSascha Wildner 	if (sc->MFA_enabled) {
349590ba11dSSascha Wildner 		return 1;
350590ba11dSSascha Wildner 	}
351590ba11dSSascha Wildner 
352590ba11dSSascha Wildner 	lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE);
353590ba11dSSascha Wildner 	if ((cm = mfi_dequeue_free(sc)) == NULL) {
354590ba11dSSascha Wildner 		lockmgr(&sc->mfi_io_lock, LK_RELEASE);
355590ba11dSSascha Wildner 		return (EBUSY);
356590ba11dSSascha Wildner 	}
357590ba11dSSascha Wildner 	cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_tb_init);
358590ba11dSSascha Wildner 	cm->cm_frame_busaddr = sc->mfi_tb_init_busaddr;
359590ba11dSSascha Wildner 	cm->cm_dmamap = sc->mfi_tb_init_dmamap;
360590ba11dSSascha Wildner 	cm->cm_frame->header.context = 0;
361590ba11dSSascha Wildner 	cm->cm_sc = sc;
362590ba11dSSascha Wildner 	cm->cm_index = 0;
363590ba11dSSascha Wildner 
364590ba11dSSascha Wildner 	/*
365590ba11dSSascha Wildner 	 * Abuse the SG list area of the frame to hold the init_qinfo
366590ba11dSSascha Wildner 	 * object;
367590ba11dSSascha Wildner 	 */
368590ba11dSSascha Wildner 	mfi_init = &cm->cm_frame->init;
369590ba11dSSascha Wildner 
370590ba11dSSascha Wildner 	bzero(mpi2IocInit, sizeof(struct MPI2_IOC_INIT_REQUEST));
371590ba11dSSascha Wildner 	mpi2IocInit->Function  = MPI2_FUNCTION_IOC_INIT;
372590ba11dSSascha Wildner 	mpi2IocInit->WhoInit   = MPI2_WHOINIT_HOST_DRIVER;
373590ba11dSSascha Wildner 
374590ba11dSSascha Wildner 	/* set MsgVersion and HeaderVersion host driver was built with */
375590ba11dSSascha Wildner 	mpi2IocInit->MsgVersion = MPI2_VERSION;
376590ba11dSSascha Wildner 	mpi2IocInit->HeaderVersion = MPI2_HEADER_VERSION;
377590ba11dSSascha Wildner 	mpi2IocInit->SystemRequestFrameSize = sc->raid_io_msg_size/4;
378590ba11dSSascha Wildner 	mpi2IocInit->ReplyDescriptorPostQueueDepth
379590ba11dSSascha Wildner 	    = (uint16_t)sc->mfi_max_fw_cmds;
380590ba11dSSascha Wildner 	mpi2IocInit->ReplyFreeQueueDepth = 0; /* Not supported by MR. */
381590ba11dSSascha Wildner 
382590ba11dSSascha Wildner 	/* Get physical address of reply frame pool */
383590ba11dSSascha Wildner 	offset = (uintptr_t) sc->reply_frame_pool_align
384590ba11dSSascha Wildner 	    - (uintptr_t)sc->request_message_pool;
385590ba11dSSascha Wildner 	phyAddress = sc->mfi_tb_busaddr + offset;
386590ba11dSSascha Wildner 	mfiAddressTemp =
387590ba11dSSascha Wildner 	    (MFI_ADDRESS *)&mpi2IocInit->ReplyDescriptorPostQueueAddress;
388590ba11dSSascha Wildner 	mfiAddressTemp->u.addressLow = (uint32_t)phyAddress;
389590ba11dSSascha Wildner 	mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32);
390590ba11dSSascha Wildner 
391590ba11dSSascha Wildner 	/* Get physical address of request message pool */
392590ba11dSSascha Wildner 	offset = sc->request_message_pool_align - sc->request_message_pool;
393590ba11dSSascha Wildner 	phyAddress =  sc->mfi_tb_busaddr + offset;
394590ba11dSSascha Wildner 	mfiAddressTemp = (MFI_ADDRESS *)&mpi2IocInit->SystemRequestFrameBaseAddress;
395590ba11dSSascha Wildner 	mfiAddressTemp->u.addressLow = (uint32_t)phyAddress;
396590ba11dSSascha Wildner 	mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32);
397590ba11dSSascha Wildner 	mpi2IocInit->ReplyFreeQueueAddress =  0; /* Not supported by MR. */
398cec73927SMatthew Dillon 	mpi2IocInit->TimeStamp = time_uptime;
399590ba11dSSascha Wildner 
400590ba11dSSascha Wildner 	if (sc->verbuf) {
401590ba11dSSascha Wildner 		ksnprintf((char *)sc->verbuf, strlen(MEGASAS_VERSION) + 2, "%s\n",
402590ba11dSSascha Wildner                 MEGASAS_VERSION);
403590ba11dSSascha Wildner 		mfi_init->driver_ver_lo = (uint32_t)sc->verbuf_h_busaddr;
404590ba11dSSascha Wildner 		mfi_init->driver_ver_hi =
405590ba11dSSascha Wildner 		    (uint32_t)((uint64_t)sc->verbuf_h_busaddr >> 32);
406590ba11dSSascha Wildner 	}
407590ba11dSSascha Wildner 	/* Get the physical address of the mpi2 ioc init command */
408590ba11dSSascha Wildner 	phyAddress =  sc->mfi_tb_ioc_init_busaddr;
409590ba11dSSascha Wildner 	mfi_init->qinfo_new_addr_lo = (uint32_t)phyAddress;
410590ba11dSSascha Wildner 	mfi_init->qinfo_new_addr_hi = (uint32_t)((uint64_t)phyAddress >> 32);
411590ba11dSSascha Wildner 	mfi_init->header.flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
412590ba11dSSascha Wildner 
413590ba11dSSascha Wildner 	mfi_init->header.cmd = MFI_CMD_INIT;
414590ba11dSSascha Wildner 	mfi_init->header.data_len = sizeof(struct MPI2_IOC_INIT_REQUEST);
415590ba11dSSascha Wildner 	mfi_init->header.cmd_status = MFI_STAT_INVALID_STATUS;
416590ba11dSSascha Wildner 
417590ba11dSSascha Wildner 	cm->cm_data = NULL;
418590ba11dSSascha Wildner 	cm->cm_flags |= MFI_CMD_POLLED;
419cec73927SMatthew Dillon 	cm->cm_timestamp = time_uptime;
420590ba11dSSascha Wildner 	if ((error = mfi_mapcmd(sc, cm)) != 0) {
421590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "failed to send IOC init2 "
422590ba11dSSascha Wildner 		    "command %d at %lx\n", error, (long)cm->cm_frame_busaddr);
423590ba11dSSascha Wildner 		mfi_release_command(cm);
424590ba11dSSascha Wildner 		lockmgr(&sc->mfi_io_lock, LK_RELEASE);
425590ba11dSSascha Wildner 		return (error);
426590ba11dSSascha Wildner 	}
427590ba11dSSascha Wildner 	mfi_release_command(cm);
428590ba11dSSascha Wildner 	lockmgr(&sc->mfi_io_lock, LK_RELEASE);
429590ba11dSSascha Wildner 
430590ba11dSSascha Wildner 	if (mfi_init->header.cmd_status == 0) {
431590ba11dSSascha Wildner 		sc->MFA_enabled = 1;
432590ba11dSSascha Wildner 	}
433590ba11dSSascha Wildner 	else {
434590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "Init command Failed %x\n",
435590ba11dSSascha Wildner 		    mfi_init->header.cmd_status);
436590ba11dSSascha Wildner 		return 1;
437590ba11dSSascha Wildner 	}
438590ba11dSSascha Wildner 
439590ba11dSSascha Wildner 	return 0;
440590ba11dSSascha Wildner 
441590ba11dSSascha Wildner }
442590ba11dSSascha Wildner 
mfi_tbolt_alloc_cmd(struct mfi_softc * sc)443590ba11dSSascha Wildner int mfi_tbolt_alloc_cmd(struct mfi_softc *sc)
444590ba11dSSascha Wildner {
445590ba11dSSascha Wildner 	struct mfi_cmd_tbolt *cmd;
446590ba11dSSascha Wildner 	bus_addr_t io_req_base_phys;
447590ba11dSSascha Wildner 	uint8_t *io_req_base;
448590ba11dSSascha Wildner 	int i = 0, j = 0, offset = 0;
449590ba11dSSascha Wildner 
450590ba11dSSascha Wildner 	/*
451590ba11dSSascha Wildner 	 * sc->mfi_cmd_pool_tbolt is an array of struct mfi_cmd_tbolt pointers.
452590ba11dSSascha Wildner 	 * Allocate the dynamic array first and then allocate individual
453590ba11dSSascha Wildner 	 * commands.
454590ba11dSSascha Wildner 	 */
455590ba11dSSascha Wildner 	sc->request_desc_pool = kmalloc(sizeof(
456590ba11dSSascha Wildner 	    union mfi_mpi2_request_descriptor) * sc->mfi_max_fw_cmds,
457590ba11dSSascha Wildner 	    M_MFIBUF, M_NOWAIT|M_ZERO);
458590ba11dSSascha Wildner 	sc->mfi_cmd_pool_tbolt = kmalloc(sizeof(struct mfi_cmd_tbolt*)
459590ba11dSSascha Wildner 	    * sc->mfi_max_fw_cmds, M_MFIBUF, M_NOWAIT|M_ZERO);
460590ba11dSSascha Wildner 
461590ba11dSSascha Wildner 	if (!sc->mfi_cmd_pool_tbolt) {
462590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "out of memory. Could not alloc "
463590ba11dSSascha Wildner 		    "memory for cmd_list_fusion\n");
464590ba11dSSascha Wildner 		return 1;
465590ba11dSSascha Wildner 	}
466590ba11dSSascha Wildner 
467590ba11dSSascha Wildner 	for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
468590ba11dSSascha Wildner 		sc->mfi_cmd_pool_tbolt[i] = kmalloc(sizeof(
469590ba11dSSascha Wildner 		    struct mfi_cmd_tbolt),M_MFIBUF, M_NOWAIT|M_ZERO);
470590ba11dSSascha Wildner 
471590ba11dSSascha Wildner 		if (!sc->mfi_cmd_pool_tbolt[i]) {
472590ba11dSSascha Wildner 			device_printf(sc->mfi_dev, "Could not alloc cmd list "
473590ba11dSSascha Wildner 			    "fusion\n");
474590ba11dSSascha Wildner 
475590ba11dSSascha Wildner 			for (j = 0; j < i; j++)
476590ba11dSSascha Wildner 				kfree(sc->mfi_cmd_pool_tbolt[j], M_MFIBUF);
477590ba11dSSascha Wildner 
478590ba11dSSascha Wildner 			kfree(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
479590ba11dSSascha Wildner 			sc->mfi_cmd_pool_tbolt = NULL;
480590ba11dSSascha Wildner 		}
481590ba11dSSascha Wildner 	}
482590ba11dSSascha Wildner 
483590ba11dSSascha Wildner 	/*
484590ba11dSSascha Wildner 	 * The first 256 bytes (SMID 0) is not used. Don't add to the cmd
485590ba11dSSascha Wildner 	 *list
486590ba11dSSascha Wildner 	 */
487590ba11dSSascha Wildner 	io_req_base = sc->request_message_pool_align
488590ba11dSSascha Wildner 		+ MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
489590ba11dSSascha Wildner 	io_req_base_phys = sc->request_msg_busaddr
490590ba11dSSascha Wildner 		+ MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
491590ba11dSSascha Wildner 
492590ba11dSSascha Wildner 	/*
493590ba11dSSascha Wildner 	 * Add all the commands to command pool (instance->cmd_pool)
494590ba11dSSascha Wildner 	 */
495590ba11dSSascha Wildner 	/* SMID 0 is reserved. Set SMID/index from 1 */
496590ba11dSSascha Wildner 
497590ba11dSSascha Wildner 	for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
498590ba11dSSascha Wildner 		cmd = sc->mfi_cmd_pool_tbolt[i];
499590ba11dSSascha Wildner 		offset = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * i;
500590ba11dSSascha Wildner 		cmd->index = i + 1;
501590ba11dSSascha Wildner 		cmd->request_desc = (union mfi_mpi2_request_descriptor *)
502590ba11dSSascha Wildner 		    (sc->request_desc_pool + i);
503590ba11dSSascha Wildner 		cmd->io_request = (struct mfi_mpi2_request_raid_scsi_io *)
504590ba11dSSascha Wildner 		    (io_req_base + offset);
505590ba11dSSascha Wildner 		cmd->io_request_phys_addr = io_req_base_phys + offset;
506590ba11dSSascha Wildner 		cmd->sg_frame = (MPI2_SGE_IO_UNION *)(sc->reply_pool_limit
507590ba11dSSascha Wildner 		    + i * MEGASAS_MAX_SZ_CHAIN_FRAME);
508590ba11dSSascha Wildner 		cmd->sg_frame_phys_addr = sc->sg_frame_busaddr + i
509590ba11dSSascha Wildner 		    * MEGASAS_MAX_SZ_CHAIN_FRAME;
510590ba11dSSascha Wildner 
511590ba11dSSascha Wildner 		TAILQ_INSERT_TAIL(&(sc->mfi_cmd_tbolt_tqh), cmd, next);
512590ba11dSSascha Wildner 	}
513590ba11dSSascha Wildner 	return 0;
514590ba11dSSascha Wildner }
515590ba11dSSascha Wildner 
mfi_tbolt_reset(struct mfi_softc * sc)516590ba11dSSascha Wildner int mfi_tbolt_reset(struct mfi_softc *sc)
517590ba11dSSascha Wildner {
518590ba11dSSascha Wildner 	uint32_t fw_state;
519590ba11dSSascha Wildner 
520590ba11dSSascha Wildner 	lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE);
521590ba11dSSascha Wildner 	if (atomic_read(&sc->fw_reset_no_pci_access)) {
522590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "NO PCI ACCESS\n");
523590ba11dSSascha Wildner 		lockmgr(&sc->mfi_io_lock, LK_RELEASE);
524590ba11dSSascha Wildner 		return 1;
525590ba11dSSascha Wildner 	}
526590ba11dSSascha Wildner 
527590ba11dSSascha Wildner 	if (sc->hw_crit_error) {
528590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "HW CRITICAL ERROR\n");
529590ba11dSSascha Wildner 		lockmgr(&sc->mfi_io_lock, LK_RELEASE);
530590ba11dSSascha Wildner 		return 1;
531590ba11dSSascha Wildner 	}
532590ba11dSSascha Wildner 
533590ba11dSSascha Wildner 	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
534590ba11dSSascha Wildner 		fw_state = sc->mfi_read_fw_status(sc);
535590ba11dSSascha Wildner 		if ((fw_state & MFI_FWSTATE_FAULT) == MFI_FWSTATE_FAULT) {
536590ba11dSSascha Wildner 			if ((sc->disableOnlineCtrlReset == 0)
537590ba11dSSascha Wildner 			    && (sc->adpreset == 0)) {
538590ba11dSSascha Wildner 				device_printf(sc->mfi_dev, "Adapter RESET "
539590ba11dSSascha Wildner 				    "condition is detected\n");
540590ba11dSSascha Wildner 				sc->adpreset = 1;
541590ba11dSSascha Wildner 				sc->issuepend_done = 0;
542590ba11dSSascha Wildner 				sc->MFA_enabled = 0;
543590ba11dSSascha Wildner 				sc->last_reply_idx = 0;
5444e1af74fSSascha Wildner 				mfi_process_fw_state_chg_isr(sc);
545590ba11dSSascha Wildner 			}
546590ba11dSSascha Wildner 			lockmgr(&sc->mfi_io_lock, LK_RELEASE);
547590ba11dSSascha Wildner 			return 0;
548590ba11dSSascha Wildner 		}
549590ba11dSSascha Wildner 	}
550590ba11dSSascha Wildner 	lockmgr(&sc->mfi_io_lock, LK_RELEASE);
551590ba11dSSascha Wildner 	return 1;
552590ba11dSSascha Wildner }
553590ba11dSSascha Wildner 
554590ba11dSSascha Wildner /*
555590ba11dSSascha Wildner  * mfi_intr_tbolt - isr entry point
556590ba11dSSascha Wildner  */
mfi_intr_tbolt(void * arg)557590ba11dSSascha Wildner void mfi_intr_tbolt(void *arg)
558590ba11dSSascha Wildner {
559590ba11dSSascha Wildner 	struct mfi_softc *sc = (struct mfi_softc *)arg;
560590ba11dSSascha Wildner 
561590ba11dSSascha Wildner 	if (sc->mfi_check_clear_intr(sc) == 1) {
562590ba11dSSascha Wildner 		return;
563590ba11dSSascha Wildner 	}
564590ba11dSSascha Wildner 	if (sc->mfi_detaching)
565590ba11dSSascha Wildner 		return;
566590ba11dSSascha Wildner 	lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE);
567590ba11dSSascha Wildner 	mfi_tbolt_complete_cmd(sc);
568590ba11dSSascha Wildner 	if (sc->mfi_flags & MFI_FLAGS_QFRZN)
569590ba11dSSascha Wildner 		sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
570590ba11dSSascha Wildner 	mfi_startio(sc);
571590ba11dSSascha Wildner 	lockmgr(&sc->mfi_io_lock, LK_RELEASE);
572590ba11dSSascha Wildner 	return;
573590ba11dSSascha Wildner }
574590ba11dSSascha Wildner 
575590ba11dSSascha Wildner /**
576590ba11dSSascha Wildner  * map_cmd_status -	Maps FW cmd status to OS cmd status
577590ba11dSSascha Wildner  * @cmd :		Pointer to cmd
578590ba11dSSascha Wildner  * @status :		status of cmd returned by FW
579590ba11dSSascha Wildner  * @ext_status :	ext status of cmd returned by FW
580590ba11dSSascha Wildner  */
581590ba11dSSascha Wildner 
582590ba11dSSascha Wildner void
map_tbolt_cmd_status(struct mfi_command * mfi_cmd,uint8_t status,uint8_t ext_status)583590ba11dSSascha Wildner map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status,
584590ba11dSSascha Wildner     uint8_t ext_status)
585590ba11dSSascha Wildner {
586590ba11dSSascha Wildner 
587590ba11dSSascha Wildner 	switch (status) {
588590ba11dSSascha Wildner 
589590ba11dSSascha Wildner 		case MFI_STAT_OK:
590590ba11dSSascha Wildner 			mfi_cmd->cm_frame->header.cmd_status = 0;
591590ba11dSSascha Wildner 			mfi_cmd->cm_frame->dcmd.header.cmd_status = 0;
592590ba11dSSascha Wildner 			break;
593590ba11dSSascha Wildner 
594590ba11dSSascha Wildner 		case MFI_STAT_SCSI_IO_FAILED:
595590ba11dSSascha Wildner 		case MFI_STAT_LD_INIT_IN_PROGRESS:
596590ba11dSSascha Wildner 			mfi_cmd->cm_frame->header.cmd_status = status;
597590ba11dSSascha Wildner 			mfi_cmd->cm_frame->header.scsi_status = ext_status;
598590ba11dSSascha Wildner 			mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
599590ba11dSSascha Wildner 			mfi_cmd->cm_frame->dcmd.header.scsi_status
600590ba11dSSascha Wildner 			    = ext_status;
601590ba11dSSascha Wildner 			break;
602590ba11dSSascha Wildner 
603590ba11dSSascha Wildner 		case MFI_STAT_SCSI_DONE_WITH_ERROR:
604590ba11dSSascha Wildner 			mfi_cmd->cm_frame->header.cmd_status = ext_status;
605590ba11dSSascha Wildner 			mfi_cmd->cm_frame->dcmd.header.cmd_status = ext_status;
606590ba11dSSascha Wildner 			break;
607590ba11dSSascha Wildner 
608590ba11dSSascha Wildner 		case MFI_STAT_LD_OFFLINE:
609590ba11dSSascha Wildner 		case MFI_STAT_DEVICE_NOT_FOUND:
610590ba11dSSascha Wildner 			mfi_cmd->cm_frame->header.cmd_status = status;
611590ba11dSSascha Wildner 			mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
612590ba11dSSascha Wildner 			break;
613590ba11dSSascha Wildner 
614590ba11dSSascha Wildner 		default:
615590ba11dSSascha Wildner 			mfi_cmd->cm_frame->header.cmd_status = status;
616590ba11dSSascha Wildner 			mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
617590ba11dSSascha Wildner 			break;
618590ba11dSSascha Wildner 		}
619590ba11dSSascha Wildner }
620590ba11dSSascha Wildner 
621590ba11dSSascha Wildner /**
622590ba11dSSascha Wildner  * mfi_tbolt_return_cmd -	Return a cmd to free command pool
623590ba11dSSascha Wildner  * @instance:		Adapter soft state
624590ba11dSSascha Wildner  * @cmd:		Command packet to be returned to free command pool
625590ba11dSSascha Wildner  */
626590ba11dSSascha Wildner static inline void
mfi_tbolt_return_cmd(struct mfi_softc * sc,struct mfi_cmd_tbolt * cmd)627590ba11dSSascha Wildner mfi_tbolt_return_cmd(struct mfi_softc *sc, struct mfi_cmd_tbolt *cmd)
628590ba11dSSascha Wildner {
629148e9c0bSSascha Wildner 	mfi_lockassert(&sc->mfi_io_lock);
630590ba11dSSascha Wildner 
631590ba11dSSascha Wildner 	TAILQ_INSERT_TAIL(&sc->mfi_cmd_tbolt_tqh, cmd, next);
632590ba11dSSascha Wildner }
633590ba11dSSascha Wildner 
mfi_tbolt_complete_cmd(struct mfi_softc * sc)634590ba11dSSascha Wildner void mfi_tbolt_complete_cmd(struct mfi_softc *sc)
635590ba11dSSascha Wildner {
636590ba11dSSascha Wildner 	struct mfi_mpi2_reply_header *desc, *reply_desc;
637590ba11dSSascha Wildner 	struct mfi_command *cmd_mfi;	/* For MFA Cmds */
638590ba11dSSascha Wildner 	struct mfi_cmd_tbolt *cmd_tbolt;
639590ba11dSSascha Wildner 	uint16_t smid;
640590ba11dSSascha Wildner 	uint8_t reply_descript_type;
641590ba11dSSascha Wildner 	struct mfi_mpi2_request_raid_scsi_io  *scsi_io_req;
642590ba11dSSascha Wildner 	uint32_t status, extStatus;
643590ba11dSSascha Wildner 	uint16_t num_completed;
644590ba11dSSascha Wildner 	union desc_value val;
645590ba11dSSascha Wildner 
646590ba11dSSascha Wildner 	desc = (struct mfi_mpi2_reply_header *)
647590ba11dSSascha Wildner 		((uintptr_t)sc->reply_frame_pool_align
648590ba11dSSascha Wildner 		+ sc->last_reply_idx * sc->reply_size);
649590ba11dSSascha Wildner 	reply_desc = desc;
650590ba11dSSascha Wildner 
651590ba11dSSascha Wildner 	if (!reply_desc)
652590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "reply desc is NULL!!\n");
653590ba11dSSascha Wildner 
654590ba11dSSascha Wildner 	reply_descript_type = reply_desc->ReplyFlags
655590ba11dSSascha Wildner 	     & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
656590ba11dSSascha Wildner 	if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
657590ba11dSSascha Wildner 		return;
658590ba11dSSascha Wildner 
659590ba11dSSascha Wildner 	num_completed = 0;
660590ba11dSSascha Wildner 	val.word = ((union mfi_mpi2_reply_descriptor *)desc)->words;
661590ba11dSSascha Wildner 
662590ba11dSSascha Wildner 	/* Read Reply descriptor */
663590ba11dSSascha Wildner 	while ((val.u.low != 0xFFFFFFFF) && (val.u.high != 0xFFFFFFFF)) {
664590ba11dSSascha Wildner 
665590ba11dSSascha Wildner 		smid = reply_desc->SMID;
666590ba11dSSascha Wildner 		if (!smid || smid > sc->mfi_max_fw_cmds + 1) {
667590ba11dSSascha Wildner 			device_printf(sc->mfi_dev, "smid is %x. Cannot "
668590ba11dSSascha Wildner 			    "proceed. Returning \n", smid);
669590ba11dSSascha Wildner 			return;
670590ba11dSSascha Wildner 		}
671590ba11dSSascha Wildner 
672590ba11dSSascha Wildner 		cmd_tbolt = sc->mfi_cmd_pool_tbolt[smid - 1];
673590ba11dSSascha Wildner 		cmd_mfi = &sc->mfi_commands[cmd_tbolt->sync_cmd_idx];
674590ba11dSSascha Wildner 		scsi_io_req = cmd_tbolt->io_request;
675590ba11dSSascha Wildner 
676590ba11dSSascha Wildner 		/* Check if internal commands */
677590ba11dSSascha Wildner 		status = cmd_mfi->cm_frame->dcmd.header.cmd_status;
678590ba11dSSascha Wildner 		extStatus = cmd_mfi->cm_frame->dcmd.header.scsi_status;
679590ba11dSSascha Wildner 
680590ba11dSSascha Wildner 		switch (scsi_io_req->Function) {
681590ba11dSSascha Wildner 		case MPI2_FUNCTION_LD_IO_REQUEST:
682590ba11dSSascha Wildner 			/* Regular Path IO. */
683590ba11dSSascha Wildner 			/* Map the Fw Error Status. */
684590ba11dSSascha Wildner 			map_tbolt_cmd_status(cmd_mfi, status,
685590ba11dSSascha Wildner 			    extStatus);
686590ba11dSSascha Wildner 			if ((cmd_mfi->cm_frame->dcmd.opcode
687590ba11dSSascha Wildner 			    == MFI_DCMD_LD_MAP_GET_INFO)
688590ba11dSSascha Wildner 			    && (cmd_mfi->cm_frame->dcmd.mbox[1] == 1)) {
689590ba11dSSascha Wildner 					if (cmd_mfi->cm_frame->header.cmd_status
690590ba11dSSascha Wildner 					    != 0)
691590ba11dSSascha Wildner 						device_printf(sc->mfi_dev,
692590ba11dSSascha Wildner 						    "map sync failed\n");
693590ba11dSSascha Wildner 					else {
694590ba11dSSascha Wildner 						sc->map_id++;
695590ba11dSSascha Wildner 						device_printf(sc->mfi_dev,
696590ba11dSSascha Wildner 						    "map sync completed\n");
697590ba11dSSascha Wildner 						mfi_release_command(cmd_mfi);
698590ba11dSSascha Wildner 					}
699590ba11dSSascha Wildner 				}
700590ba11dSSascha Wildner 			if ((cmd_mfi->cm_flags & MFI_ON_MFIQ_BUSY)
701590ba11dSSascha Wildner 			    == MFI_ON_MFIQ_BUSY
702590ba11dSSascha Wildner 			    && (cmd_mfi->cm_flags & MFI_CMD_POLLED) == 0) {
703590ba11dSSascha Wildner 				/* BHARAT poll workaround */
704590ba11dSSascha Wildner 				mfi_remove_busy(cmd_mfi);
705590ba11dSSascha Wildner 				cmd_mfi->cm_error = 0;
706590ba11dSSascha Wildner 				mfi_complete(sc, cmd_mfi);
707590ba11dSSascha Wildner 			}
708590ba11dSSascha Wildner 			mfi_tbolt_return_cmd(sc, cmd_tbolt);
709590ba11dSSascha Wildner 			break;
710590ba11dSSascha Wildner 		case MPI2_FUNCTION_PASSTHRU_IO_REQUEST:
711590ba11dSSascha Wildner 			map_tbolt_cmd_status(cmd_mfi, status, extStatus);
712590ba11dSSascha Wildner 			if ((cmd_mfi->cm_frame->dcmd.opcode
713590ba11dSSascha Wildner 			    == MFI_DCMD_LD_MAP_GET_INFO)
714590ba11dSSascha Wildner 			    && (cmd_mfi->cm_frame->dcmd.mbox[1] == 1)) {
715590ba11dSSascha Wildner 				if (cmd_mfi->cm_frame->header.cmd_status != 0)
716590ba11dSSascha Wildner 					device_printf(sc->mfi_dev,
717590ba11dSSascha Wildner 					    "map sync failed\n");
718590ba11dSSascha Wildner 				else {
719590ba11dSSascha Wildner 					sc->map_id++;
720590ba11dSSascha Wildner 					device_printf(sc->mfi_dev,
721590ba11dSSascha Wildner 					    "map sync completed\n");
722590ba11dSSascha Wildner 					mfi_release_command(cmd_mfi);
723590ba11dSSascha Wildner 				}
724590ba11dSSascha Wildner 			}
725590ba11dSSascha Wildner 			if ((cmd_mfi->cm_flags & MFI_ON_MFIQ_BUSY)
726590ba11dSSascha Wildner 			    == MFI_ON_MFIQ_BUSY
727590ba11dSSascha Wildner 			    && (cmd_mfi->cm_flags & MFI_CMD_POLLED) == 0) {
728590ba11dSSascha Wildner 				/* BHARAT poll workaround */
729590ba11dSSascha Wildner 				mfi_remove_busy(cmd_mfi);
730590ba11dSSascha Wildner 				cmd_mfi->cm_error = 0;
731590ba11dSSascha Wildner 				mfi_complete(sc, cmd_mfi);
732590ba11dSSascha Wildner 			}
733590ba11dSSascha Wildner 			mfi_tbolt_return_cmd(sc, cmd_tbolt);
734590ba11dSSascha Wildner 			break;
735590ba11dSSascha Wildner 		}
736590ba11dSSascha Wildner 
737590ba11dSSascha Wildner 		sc->last_reply_idx++;
738590ba11dSSascha Wildner 		if (sc->last_reply_idx >= sc->mfi_max_fw_cmds) {
739590ba11dSSascha Wildner 			MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
740590ba11dSSascha Wildner 			sc->last_reply_idx = 0;
741590ba11dSSascha Wildner 		}
742590ba11dSSascha Wildner 		/*set it back to all 0xfff.*/
743590ba11dSSascha Wildner 		((union mfi_mpi2_reply_descriptor*)desc)->words =
744590ba11dSSascha Wildner 			~((uint64_t)0x00);
745590ba11dSSascha Wildner 
746590ba11dSSascha Wildner 		num_completed++;
747590ba11dSSascha Wildner 
748590ba11dSSascha Wildner 		/* Get the next reply descriptor */
749590ba11dSSascha Wildner 		desc = (struct mfi_mpi2_reply_header *)
750590ba11dSSascha Wildner 		    ((uintptr_t)sc->reply_frame_pool_align
751590ba11dSSascha Wildner 		    + sc->last_reply_idx * sc->reply_size);
752590ba11dSSascha Wildner 		reply_desc = desc;
753590ba11dSSascha Wildner 		val.word = ((union mfi_mpi2_reply_descriptor*)desc)->words;
754590ba11dSSascha Wildner 		reply_descript_type = reply_desc->ReplyFlags
755590ba11dSSascha Wildner 		    & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
756590ba11dSSascha Wildner 		if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
757590ba11dSSascha Wildner 			break;
758590ba11dSSascha Wildner 	}
759590ba11dSSascha Wildner 
760590ba11dSSascha Wildner 	if (!num_completed)
761590ba11dSSascha Wildner 		return;
762590ba11dSSascha Wildner 
763590ba11dSSascha Wildner 	/* update replyIndex to FW */
764590ba11dSSascha Wildner 	if (sc->last_reply_idx)
765590ba11dSSascha Wildner 		MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
766590ba11dSSascha Wildner 
767590ba11dSSascha Wildner 	return;
768590ba11dSSascha Wildner }
769590ba11dSSascha Wildner 
770590ba11dSSascha Wildner /**
771590ba11dSSascha Wildner  * mfi_get_cmd -	Get a command from the free pool
772590ba11dSSascha Wildner  * @instance:		Adapter soft state
773590ba11dSSascha Wildner  *
774590ba11dSSascha Wildner  * Returns a free command from the pool
775590ba11dSSascha Wildner  */
776590ba11dSSascha Wildner 
mfi_tbolt_get_cmd(struct mfi_softc * sc)777590ba11dSSascha Wildner struct mfi_cmd_tbolt *mfi_tbolt_get_cmd(struct mfi_softc
778590ba11dSSascha Wildner 						  *sc)
779590ba11dSSascha Wildner {
780590ba11dSSascha Wildner 	struct mfi_cmd_tbolt *cmd = NULL;
781590ba11dSSascha Wildner 
782148e9c0bSSascha Wildner 	mfi_lockassert(&sc->mfi_io_lock);
783590ba11dSSascha Wildner 
784590ba11dSSascha Wildner 	cmd = TAILQ_FIRST(&sc->mfi_cmd_tbolt_tqh);
785590ba11dSSascha Wildner 	TAILQ_REMOVE(&sc->mfi_cmd_tbolt_tqh, cmd, next);
786590ba11dSSascha Wildner 	memset((uint8_t *)cmd->sg_frame, 0, MEGASAS_MAX_SZ_CHAIN_FRAME);
787590ba11dSSascha Wildner 	memset((uint8_t *)cmd->io_request, 0,
788590ba11dSSascha Wildner 	    MEGASAS_THUNDERBOLT_NEW_MSG_SIZE);
789590ba11dSSascha Wildner 	return cmd;
790590ba11dSSascha Wildner }
791590ba11dSSascha Wildner 
792590ba11dSSascha Wildner union mfi_mpi2_request_descriptor *
mfi_tbolt_get_request_descriptor(struct mfi_softc * sc,uint16_t index)793590ba11dSSascha Wildner mfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index)
794590ba11dSSascha Wildner {
795590ba11dSSascha Wildner 	uint8_t *p;
796590ba11dSSascha Wildner 
797590ba11dSSascha Wildner 	if (index >= sc->mfi_max_fw_cmds) {
798590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "Invalid SMID (0x%x)request "
799590ba11dSSascha Wildner 		    "for descriptor\n", index);
800590ba11dSSascha Wildner 		return NULL;
801590ba11dSSascha Wildner 	}
802590ba11dSSascha Wildner 	p = sc->request_desc_pool + sizeof(union mfi_mpi2_request_descriptor)
803590ba11dSSascha Wildner 	    * index;
804590ba11dSSascha Wildner 	memset(p, 0, sizeof(union mfi_mpi2_request_descriptor));
805590ba11dSSascha Wildner 	return (union mfi_mpi2_request_descriptor *)p;
806590ba11dSSascha Wildner }
807590ba11dSSascha Wildner 
808590ba11dSSascha Wildner 
809590ba11dSSascha Wildner /* Used to build IOCTL cmd */
810590ba11dSSascha Wildner uint8_t
mfi_build_mpt_pass_thru(struct mfi_softc * sc,struct mfi_command * mfi_cmd)811590ba11dSSascha Wildner mfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd)
812590ba11dSSascha Wildner {
813590ba11dSSascha Wildner 	MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain;
814590ba11dSSascha Wildner 	struct mfi_mpi2_request_raid_scsi_io *io_req;
815590ba11dSSascha Wildner 	struct mfi_cmd_tbolt *cmd;
816590ba11dSSascha Wildner 
817590ba11dSSascha Wildner 	cmd = mfi_tbolt_get_cmd(sc);
818590ba11dSSascha Wildner 	if (!cmd)
819590ba11dSSascha Wildner 		return EBUSY;
820590ba11dSSascha Wildner 	mfi_cmd->cm_extra_frames = cmd->index; /* Frame count used as SMID */
821590ba11dSSascha Wildner 	cmd->sync_cmd_idx = mfi_cmd->cm_index;
822590ba11dSSascha Wildner 	io_req = cmd->io_request;
823590ba11dSSascha Wildner 	mpi25_ieee_chain = (MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;
824590ba11dSSascha Wildner 
825590ba11dSSascha Wildner 	io_req->Function = MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
826590ba11dSSascha Wildner 	io_req->SGLOffset0 = offsetof(struct mfi_mpi2_request_raid_scsi_io,
827590ba11dSSascha Wildner 	    SGL) / 4;
828590ba11dSSascha Wildner 	io_req->ChainOffset = sc->chain_offset_value_for_mpt_ptmsg;
829590ba11dSSascha Wildner 
830590ba11dSSascha Wildner 	mpi25_ieee_chain->Address = mfi_cmd->cm_frame_busaddr;
831590ba11dSSascha Wildner 
832590ba11dSSascha Wildner 	/*
833590ba11dSSascha Wildner 	  In MFI pass thru, nextChainOffset will always be zero to
834590ba11dSSascha Wildner 	  indicate the end of the chain.
835590ba11dSSascha Wildner 	*/
836590ba11dSSascha Wildner 	mpi25_ieee_chain->Flags= MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT
837590ba11dSSascha Wildner 		| MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
838590ba11dSSascha Wildner 
839590ba11dSSascha Wildner 	/* setting the length to the maximum length */
840590ba11dSSascha Wildner 	mpi25_ieee_chain->Length = 1024;
841590ba11dSSascha Wildner 
842590ba11dSSascha Wildner 	return 0;
843590ba11dSSascha Wildner }
844590ba11dSSascha Wildner 
845590ba11dSSascha Wildner void
mfi_tbolt_build_ldio(struct mfi_softc * sc,struct mfi_command * mfi_cmd,struct mfi_cmd_tbolt * cmd)846590ba11dSSascha Wildner mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
847590ba11dSSascha Wildner     struct mfi_cmd_tbolt *cmd)
848590ba11dSSascha Wildner {
849590ba11dSSascha Wildner 	uint32_t start_lba_lo = 0, start_lba_hi = 0, device_id;
850590ba11dSSascha Wildner 	struct mfi_mpi2_request_raid_scsi_io	*io_request;
851590ba11dSSascha Wildner 	struct IO_REQUEST_INFO io_info;
852590ba11dSSascha Wildner 
853590ba11dSSascha Wildner 	device_id = mfi_cmd->cm_frame->io.header.target_id;
854590ba11dSSascha Wildner 	io_request = cmd->io_request;
855590ba11dSSascha Wildner 	io_request->RaidContext.TargetID = device_id;
856590ba11dSSascha Wildner 	io_request->RaidContext.Status = 0;
857590ba11dSSascha Wildner 	io_request->RaidContext.exStatus =0;
858590ba11dSSascha Wildner 
859590ba11dSSascha Wildner 	start_lba_lo = mfi_cmd->cm_frame->io.lba_lo;
860590ba11dSSascha Wildner 	start_lba_hi = mfi_cmd->cm_frame->io.lba_hi;
861590ba11dSSascha Wildner 
862590ba11dSSascha Wildner 	memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO));
863590ba11dSSascha Wildner 	io_info.ldStartBlock = ((uint64_t)start_lba_hi << 32) | start_lba_lo;
864590ba11dSSascha Wildner 	io_info.numBlocks = mfi_cmd->cm_frame->io.header.data_len;
865590ba11dSSascha Wildner 	io_info.ldTgtId = device_id;
866590ba11dSSascha Wildner 	if ((mfi_cmd->cm_frame->header.flags & MFI_FRAME_DIR_READ) ==
867590ba11dSSascha Wildner 	    MFI_FRAME_DIR_READ)
868590ba11dSSascha Wildner 		io_info.isRead = 1;
869590ba11dSSascha Wildner 
870c5b95a56SSascha Wildner 	io_request->RaidContext.timeoutValue = MFI_FUSION_FP_DEFAULT_TIMEOUT;
871590ba11dSSascha Wildner 	io_request->Function = MPI2_FUNCTION_LD_IO_REQUEST;
872590ba11dSSascha Wildner 	io_request->DevHandle = device_id;
873c5b95a56SSascha Wildner 	cmd->request_desc->header.RequestFlags =
874c5b95a56SSascha Wildner 	    (MFI_REQ_DESCRIPT_FLAGS_LD_IO << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
875590ba11dSSascha Wildner 	if ((io_request->IoFlags == 6) && (io_info.numBlocks == 0))
876590ba11dSSascha Wildner 		io_request->RaidContext.RegLockLength = 0x100;
877590ba11dSSascha Wildner 	io_request->DataLength = mfi_cmd->cm_frame->io.header.data_len
878590ba11dSSascha Wildner 	    * MFI_SECTOR_LEN;
879590ba11dSSascha Wildner }
880590ba11dSSascha Wildner 
mfi_tbolt_is_ldio(struct mfi_command * mfi_cmd)881590ba11dSSascha Wildner int mfi_tbolt_is_ldio(struct mfi_command *mfi_cmd)
882590ba11dSSascha Wildner {
883590ba11dSSascha Wildner 	if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_READ
884590ba11dSSascha Wildner 	    || mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
885590ba11dSSascha Wildner 		return 1;
886590ba11dSSascha Wildner 	else
887590ba11dSSascha Wildner 		return 0;
888590ba11dSSascha Wildner }
889590ba11dSSascha Wildner 
890590ba11dSSascha Wildner int
mfi_tbolt_build_io(struct mfi_softc * sc,struct mfi_command * mfi_cmd,struct mfi_cmd_tbolt * cmd)891590ba11dSSascha Wildner mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd, struct mfi_cmd_tbolt *cmd)
892590ba11dSSascha Wildner {
893590ba11dSSascha Wildner 	uint32_t sge_count;
894590ba11dSSascha Wildner 	uint8_t cdb[32], cdb_len;
895590ba11dSSascha Wildner 
896590ba11dSSascha Wildner 	memset(cdb, 0, 32);
897590ba11dSSascha Wildner 	struct mfi_mpi2_request_raid_scsi_io *io_request = cmd->io_request;
898590ba11dSSascha Wildner 
899590ba11dSSascha Wildner 	/* Have to build CDB here for TB as BSD don't have a scsi layer */
900590ba11dSSascha Wildner 	if ((cdb_len = mfi_tbolt_build_cdb(sc, mfi_cmd, cdb)) == 1)
901590ba11dSSascha Wildner 		return 1;
902590ba11dSSascha Wildner 
903590ba11dSSascha Wildner 	/* Just the CDB length,rest of the Flags are zero */
904590ba11dSSascha Wildner 	io_request->IoFlags = cdb_len;
905590ba11dSSascha Wildner 	memcpy(io_request->CDB.CDB32, cdb, 32);
906590ba11dSSascha Wildner 
907590ba11dSSascha Wildner 	if (mfi_tbolt_is_ldio(mfi_cmd))
908590ba11dSSascha Wildner 		mfi_tbolt_build_ldio(sc, mfi_cmd , cmd);
909590ba11dSSascha Wildner 	else
910590ba11dSSascha Wildner 		return 1;
911590ba11dSSascha Wildner 
912590ba11dSSascha Wildner 	/*
913590ba11dSSascha Wildner 	 * Construct SGL
914590ba11dSSascha Wildner 	 */
915590ba11dSSascha Wildner 	sge_count = mfi_tbolt_make_sgl(sc, mfi_cmd,
916590ba11dSSascha Wildner 	    (pMpi25IeeeSgeChain64_t) &io_request->SGL, cmd);
917590ba11dSSascha Wildner 	if (sge_count > sc->mfi_max_sge) {
918590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "Error. sge_count (0x%x) exceeds "
919590ba11dSSascha Wildner 		    "max (0x%x) allowed\n", sge_count, sc->mfi_max_sge);
920590ba11dSSascha Wildner 		return 1;
921590ba11dSSascha Wildner 	}
922590ba11dSSascha Wildner 	io_request->RaidContext.numSGE = sge_count;
923590ba11dSSascha Wildner 	io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
924590ba11dSSascha Wildner 
925590ba11dSSascha Wildner 	if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
926590ba11dSSascha Wildner 		io_request->Control = MPI2_SCSIIO_CONTROL_WRITE;
927590ba11dSSascha Wildner 	else
928590ba11dSSascha Wildner 		io_request->Control = MPI2_SCSIIO_CONTROL_READ;
929590ba11dSSascha Wildner 
930590ba11dSSascha Wildner 	io_request->SGLOffset0 = offsetof(
931590ba11dSSascha Wildner 	    struct mfi_mpi2_request_raid_scsi_io, SGL)/4;
932590ba11dSSascha Wildner 
933590ba11dSSascha Wildner 	io_request->SenseBufferLowAddress = mfi_cmd->cm_sense_busaddr;
934590ba11dSSascha Wildner 	io_request->SenseBufferLength = MFI_SENSE_LEN;
935590ba11dSSascha Wildner 	return 0;
936590ba11dSSascha Wildner }
937590ba11dSSascha Wildner 
938590ba11dSSascha Wildner static int
mfi_tbolt_build_cdb(struct mfi_softc * sc,struct mfi_command * mfi_cmd,uint8_t * cdb)939590ba11dSSascha Wildner mfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
940590ba11dSSascha Wildner     uint8_t *cdb)
941590ba11dSSascha Wildner {
942590ba11dSSascha Wildner 	uint32_t lba_lo, lba_hi, num_lba;
943590ba11dSSascha Wildner 	uint8_t cdb_len;
944590ba11dSSascha Wildner 
945590ba11dSSascha Wildner 	if (mfi_cmd == NULL || cdb == NULL)
946590ba11dSSascha Wildner 		return 1;
947590ba11dSSascha Wildner 	num_lba = mfi_cmd->cm_frame->io.header.data_len;
948590ba11dSSascha Wildner 	lba_lo = mfi_cmd->cm_frame->io.lba_lo;
949590ba11dSSascha Wildner 	lba_hi = mfi_cmd->cm_frame->io.lba_hi;
950590ba11dSSascha Wildner 
951590ba11dSSascha Wildner 	if ((num_lba <= 0xFF) && (lba_lo <= 0x1FFFFF)) {
952590ba11dSSascha Wildner 		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
953590ba11dSSascha Wildner 			/* Read 6 or Write 6 */
954590ba11dSSascha Wildner 			cdb[0] = (uint8_t) (0x0A);
955590ba11dSSascha Wildner 		else
956590ba11dSSascha Wildner 			cdb[0] = (uint8_t) (0x08);
957590ba11dSSascha Wildner 
958590ba11dSSascha Wildner 		cdb[4] = (uint8_t) num_lba;
959590ba11dSSascha Wildner 		cdb[3] = (uint8_t) (lba_lo & 0xFF);
960590ba11dSSascha Wildner 		cdb[2] = (uint8_t) (lba_lo >> 8);
961590ba11dSSascha Wildner 		cdb[1] = (uint8_t) ((lba_lo >> 16) & 0x1F);
962590ba11dSSascha Wildner 		cdb_len = 6;
963590ba11dSSascha Wildner 	} else if ((num_lba <= 0xFFFF) && (lba_lo <= 0xFFFFFFFF)) {
964590ba11dSSascha Wildner 		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
965590ba11dSSascha Wildner 			/* Read 10 or Write 10 */
966590ba11dSSascha Wildner 			cdb[0] = (uint8_t) (0x2A);
967590ba11dSSascha Wildner 		else
968590ba11dSSascha Wildner 			cdb[0] = (uint8_t) (0x28);
969590ba11dSSascha Wildner 		cdb[8] = (uint8_t) (num_lba & 0xFF);
970590ba11dSSascha Wildner 		cdb[7] = (uint8_t) (num_lba >> 8);
971590ba11dSSascha Wildner 		cdb[5] = (uint8_t) (lba_lo & 0xFF);
972590ba11dSSascha Wildner 		cdb[4] = (uint8_t) (lba_lo >> 8);
973590ba11dSSascha Wildner 		cdb[3] = (uint8_t) (lba_lo >> 16);
974590ba11dSSascha Wildner 		cdb[2] = (uint8_t) (lba_lo >> 24);
975590ba11dSSascha Wildner 		cdb_len = 10;
976590ba11dSSascha Wildner 	} else if ((num_lba > 0xFFFF) && (lba_hi == 0)) {
977590ba11dSSascha Wildner 		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
978590ba11dSSascha Wildner 			/* Read 12 or Write 12 */
979590ba11dSSascha Wildner 			cdb[0] = (uint8_t) (0xAA);
980590ba11dSSascha Wildner 		else
981590ba11dSSascha Wildner 			cdb[0] = (uint8_t) (0xA8);
982590ba11dSSascha Wildner 		cdb[9] = (uint8_t) (num_lba & 0xFF);
983590ba11dSSascha Wildner 		cdb[8] = (uint8_t) (num_lba >> 8);
984590ba11dSSascha Wildner 		cdb[7] = (uint8_t) (num_lba >> 16);
985590ba11dSSascha Wildner 		cdb[6] = (uint8_t) (num_lba >> 24);
986590ba11dSSascha Wildner 		cdb[5] = (uint8_t) (lba_lo & 0xFF);
987590ba11dSSascha Wildner 		cdb[4] = (uint8_t) (lba_lo >> 8);
988590ba11dSSascha Wildner 		cdb[3] = (uint8_t) (lba_lo >> 16);
989590ba11dSSascha Wildner 		cdb[2] = (uint8_t) (lba_lo >> 24);
990590ba11dSSascha Wildner 		cdb_len = 12;
991590ba11dSSascha Wildner 	} else {
992590ba11dSSascha Wildner 		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
993590ba11dSSascha Wildner 			cdb[0] = (uint8_t) (0x8A);
994590ba11dSSascha Wildner 		else
995590ba11dSSascha Wildner 			cdb[0] = (uint8_t) (0x88);
996590ba11dSSascha Wildner 		cdb[13] = (uint8_t) (num_lba & 0xFF);
997590ba11dSSascha Wildner 		cdb[12] = (uint8_t) (num_lba >> 8);
998590ba11dSSascha Wildner 		cdb[11] = (uint8_t) (num_lba >> 16);
999590ba11dSSascha Wildner 		cdb[10] = (uint8_t) (num_lba >> 24);
1000590ba11dSSascha Wildner 		cdb[9] = (uint8_t) (lba_lo & 0xFF);
1001590ba11dSSascha Wildner 		cdb[8] = (uint8_t) (lba_lo >> 8);
1002590ba11dSSascha Wildner 		cdb[7] = (uint8_t) (lba_lo >> 16);
1003590ba11dSSascha Wildner 		cdb[6] = (uint8_t) (lba_lo >> 24);
1004590ba11dSSascha Wildner 		cdb[5] = (uint8_t) (lba_hi & 0xFF);
1005590ba11dSSascha Wildner 		cdb[4] = (uint8_t) (lba_hi >> 8);
1006590ba11dSSascha Wildner 		cdb[3] = (uint8_t) (lba_hi >> 16);
1007590ba11dSSascha Wildner 		cdb[2] = (uint8_t) (lba_hi >> 24);
1008590ba11dSSascha Wildner 		cdb_len = 16;
1009590ba11dSSascha Wildner 	}
1010590ba11dSSascha Wildner 	return cdb_len;
1011590ba11dSSascha Wildner }
1012590ba11dSSascha Wildner 
1013590ba11dSSascha Wildner static int
mfi_tbolt_make_sgl(struct mfi_softc * sc,struct mfi_command * mfi_cmd,pMpi25IeeeSgeChain64_t sgl_ptr,struct mfi_cmd_tbolt * cmd)1014590ba11dSSascha Wildner mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
1015590ba11dSSascha Wildner 		   pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd)
1016590ba11dSSascha Wildner {
1017489fe090SSascha Wildner 	uint8_t i, sg_processed;
1018590ba11dSSascha Wildner 	uint8_t sge_count, sge_idx;
1019590ba11dSSascha Wildner 	union mfi_sgl *os_sgl;
1020590ba11dSSascha Wildner 
1021590ba11dSSascha Wildner 	/*
1022590ba11dSSascha Wildner 	 * Return 0 if there is no data transfer
1023590ba11dSSascha Wildner 	 */
1024590ba11dSSascha Wildner 	if (!mfi_cmd->cm_sg || !mfi_cmd->cm_len) {
1025590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "Buffer empty \n");
1026590ba11dSSascha Wildner 		return 0;
1027590ba11dSSascha Wildner 	}
1028590ba11dSSascha Wildner 	os_sgl = mfi_cmd->cm_sg;
1029590ba11dSSascha Wildner 	sge_count = mfi_cmd->cm_frame->header.sg_count;
1030590ba11dSSascha Wildner 
1031590ba11dSSascha Wildner 	if (sge_count > sc->mfi_max_sge) {
1032590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "sgl ptr %p sg_cnt %d \n",
1033590ba11dSSascha Wildner 		    os_sgl, sge_count);
1034590ba11dSSascha Wildner 		return sge_count;
1035590ba11dSSascha Wildner 	}
1036590ba11dSSascha Wildner 
1037590ba11dSSascha Wildner 	if (sge_count > sc->max_SGEs_in_main_message)
1038590ba11dSSascha Wildner 		/* One element to store the chain info */
1039590ba11dSSascha Wildner 		sge_idx = sc->max_SGEs_in_main_message - 1;
1040590ba11dSSascha Wildner 	else
1041590ba11dSSascha Wildner 		sge_idx = sge_count;
1042590ba11dSSascha Wildner 
1043590ba11dSSascha Wildner 	for (i = 0; i < sge_idx; i++) {
1044590ba11dSSascha Wildner 		/*
1045590ba11dSSascha Wildner 		 * For 32bit BSD we are getting 32 bit SGL's from OS
1046590ba11dSSascha Wildner 		 * but FW only take 64 bit SGL's so copying from 32 bit
1047590ba11dSSascha Wildner 		 * SGL's to 64.
1048590ba11dSSascha Wildner 		 */
1049590ba11dSSascha Wildner 		if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
1050590ba11dSSascha Wildner 			sgl_ptr->Length = os_sgl->sg_skinny[i].len;
1051590ba11dSSascha Wildner 			sgl_ptr->Address = os_sgl->sg_skinny[i].addr;
1052590ba11dSSascha Wildner 		} else {
1053590ba11dSSascha Wildner 			sgl_ptr->Length = os_sgl->sg32[i].len;
1054590ba11dSSascha Wildner 			sgl_ptr->Address = os_sgl->sg32[i].addr;
1055590ba11dSSascha Wildner 		}
1056590ba11dSSascha Wildner 		sgl_ptr->Flags = 0;
1057590ba11dSSascha Wildner 		sgl_ptr++;
1058590ba11dSSascha Wildner 		cmd->io_request->ChainOffset = 0;
1059590ba11dSSascha Wildner 	}
1060590ba11dSSascha Wildner 
1061590ba11dSSascha Wildner 	sg_processed = i;
1062590ba11dSSascha Wildner 
1063590ba11dSSascha Wildner 	if (sg_processed < sge_count) {
1064590ba11dSSascha Wildner 		pMpi25IeeeSgeChain64_t sg_chain;
1065590ba11dSSascha Wildner 		cmd->io_request->ChainOffset =
1066590ba11dSSascha Wildner 		    sc->chain_offset_value_for_main_message;
1067590ba11dSSascha Wildner 		sg_chain = sgl_ptr;
1068590ba11dSSascha Wildner 		/* Prepare chain element */
1069590ba11dSSascha Wildner 		sg_chain->NextChainOffset = 0;
1070590ba11dSSascha Wildner 		sg_chain->Flags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
1071590ba11dSSascha Wildner 		    MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
1072590ba11dSSascha Wildner 		sg_chain->Length =  (sizeof(MPI2_SGE_IO_UNION) *
1073590ba11dSSascha Wildner 		    (sge_count - sg_processed));
1074590ba11dSSascha Wildner 		sg_chain->Address = cmd->sg_frame_phys_addr;
1075590ba11dSSascha Wildner 		sgl_ptr = (pMpi25IeeeSgeChain64_t)cmd->sg_frame;
1076590ba11dSSascha Wildner 		for (; i < sge_count; i++) {
1077590ba11dSSascha Wildner 			if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
1078590ba11dSSascha Wildner 				sgl_ptr->Length = os_sgl->sg_skinny[i].len;
1079590ba11dSSascha Wildner 				sgl_ptr->Address = os_sgl->sg_skinny[i].addr;
1080590ba11dSSascha Wildner 			} else {
1081590ba11dSSascha Wildner 				sgl_ptr->Length = os_sgl->sg32[i].len;
1082590ba11dSSascha Wildner 				sgl_ptr->Address = os_sgl->sg32[i].addr;
1083590ba11dSSascha Wildner 			}
1084590ba11dSSascha Wildner 			sgl_ptr->Flags = 0;
1085590ba11dSSascha Wildner 			sgl_ptr++;
1086590ba11dSSascha Wildner 		}
1087590ba11dSSascha Wildner 	}
1088590ba11dSSascha Wildner 	return sge_count;
1089590ba11dSSascha Wildner }
1090590ba11dSSascha Wildner 
1091590ba11dSSascha Wildner union mfi_mpi2_request_descriptor *
mfi_build_and_issue_cmd(struct mfi_softc * sc,struct mfi_command * mfi_cmd)1092590ba11dSSascha Wildner mfi_build_and_issue_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd)
1093590ba11dSSascha Wildner {
1094590ba11dSSascha Wildner 	struct mfi_cmd_tbolt *cmd;
1095590ba11dSSascha Wildner 	union mfi_mpi2_request_descriptor *req_desc = NULL;
1096590ba11dSSascha Wildner 	uint16_t index;
1097590ba11dSSascha Wildner 	cmd = mfi_tbolt_get_cmd(sc);
1098590ba11dSSascha Wildner 	if (!cmd)
1099590ba11dSSascha Wildner 		return NULL;
1100590ba11dSSascha Wildner 	mfi_cmd->cm_extra_frames = cmd->index;
1101590ba11dSSascha Wildner 	cmd->sync_cmd_idx = mfi_cmd->cm_index;
1102590ba11dSSascha Wildner 
1103590ba11dSSascha Wildner 	index = cmd->index;
1104590ba11dSSascha Wildner 	req_desc = mfi_tbolt_get_request_descriptor(sc, index-1);
1105590ba11dSSascha Wildner 	if (mfi_tbolt_build_io(sc, mfi_cmd, cmd))
1106590ba11dSSascha Wildner 		return NULL;
1107590ba11dSSascha Wildner 	req_desc->header.SMID = index;
1108590ba11dSSascha Wildner 	return req_desc;
1109590ba11dSSascha Wildner }
1110590ba11dSSascha Wildner 
1111590ba11dSSascha Wildner union mfi_mpi2_request_descriptor *
mfi_tbolt_build_mpt_cmd(struct mfi_softc * sc,struct mfi_command * cmd)1112590ba11dSSascha Wildner mfi_tbolt_build_mpt_cmd(struct mfi_softc *sc, struct mfi_command *cmd)
1113590ba11dSSascha Wildner {
1114590ba11dSSascha Wildner 	union mfi_mpi2_request_descriptor *req_desc = NULL;
1115590ba11dSSascha Wildner 	uint16_t index;
1116590ba11dSSascha Wildner 	if (mfi_build_mpt_pass_thru(sc, cmd)) {
1117590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "Couldn't build MFI pass thru "
1118590ba11dSSascha Wildner 		    "cmd\n");
1119590ba11dSSascha Wildner 		return NULL;
1120590ba11dSSascha Wildner 	}
1121590ba11dSSascha Wildner 	/* For fusion the frame_count variable is used for SMID */
1122590ba11dSSascha Wildner 	index = cmd->cm_extra_frames;
1123590ba11dSSascha Wildner 
1124590ba11dSSascha Wildner 	req_desc = mfi_tbolt_get_request_descriptor(sc, index - 1);
1125590ba11dSSascha Wildner 	if (!req_desc)
1126590ba11dSSascha Wildner 		return NULL;
1127590ba11dSSascha Wildner 
1128277dbd16SSascha Wildner 	bzero(req_desc, sizeof(*req_desc));
1129590ba11dSSascha Wildner 	req_desc->header.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
1130590ba11dSSascha Wildner 	    MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
1131590ba11dSSascha Wildner 	req_desc->header.SMID = index;
1132590ba11dSSascha Wildner 	return req_desc;
1133590ba11dSSascha Wildner }
1134590ba11dSSascha Wildner 
1135590ba11dSSascha Wildner int
mfi_tbolt_send_frame(struct mfi_softc * sc,struct mfi_command * cm)1136590ba11dSSascha Wildner mfi_tbolt_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
1137590ba11dSSascha Wildner {
1138590ba11dSSascha Wildner 	struct mfi_frame_header *hdr;
1139590ba11dSSascha Wildner 	uint8_t *cdb;
1140590ba11dSSascha Wildner 	union mfi_mpi2_request_descriptor *req_desc = NULL;
1141590ba11dSSascha Wildner 	int tm = MFI_POLL_TIMEOUT_SECS * 1000;
1142590ba11dSSascha Wildner 
1143590ba11dSSascha Wildner 	hdr = &cm->cm_frame->header;
1144590ba11dSSascha Wildner 	cdb = cm->cm_frame->pass.cdb;
1145590ba11dSSascha Wildner 	if (sc->adpreset)
1146590ba11dSSascha Wildner 		return 1;
1147590ba11dSSascha Wildner 	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
1148cec73927SMatthew Dillon 		cm->cm_timestamp = time_uptime;
1149590ba11dSSascha Wildner 		mfi_enqueue_busy(cm);
1150590ba11dSSascha Wildner 	}
1151590ba11dSSascha Wildner 	else {
1152590ba11dSSascha Wildner 		hdr->cmd_status = 0xff;
1153590ba11dSSascha Wildner 		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
1154590ba11dSSascha Wildner 	}
1155590ba11dSSascha Wildner 
1156590ba11dSSascha Wildner 	if (hdr->cmd == MFI_CMD_PD_SCSI_IO) {
1157590ba11dSSascha Wildner 		/* check for inquiry commands coming from CLI */
1158*43926ee4SSascha Wildner 		if (cdb[0] != 0x28 && cdb[0] != 0x2A) {
1159590ba11dSSascha Wildner 			if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) ==
1160590ba11dSSascha Wildner 			    NULL) {
1161590ba11dSSascha Wildner 				device_printf(sc->mfi_dev, "Mapping from MFI "
1162590ba11dSSascha Wildner 				    "to MPT Failed \n");
1163590ba11dSSascha Wildner 				return 1;
1164590ba11dSSascha Wildner 			}
1165590ba11dSSascha Wildner 		}
1166590ba11dSSascha Wildner 		else
1167590ba11dSSascha Wildner 			device_printf(sc->mfi_dev, "DJA NA XXX SYSPDIO\n");
1168590ba11dSSascha Wildner 	}
1169590ba11dSSascha Wildner 	else if (hdr->cmd == MFI_CMD_LD_SCSI_IO ||
1170590ba11dSSascha Wildner 	    hdr->cmd == MFI_CMD_LD_READ || hdr->cmd == MFI_CMD_LD_WRITE) {
1171590ba11dSSascha Wildner 		if ((req_desc = mfi_build_and_issue_cmd(sc, cm)) == NULL) {
1172590ba11dSSascha Wildner 			device_printf(sc->mfi_dev, "LDIO Failed \n");
1173590ba11dSSascha Wildner 			return 1;
1174590ba11dSSascha Wildner 		}
1175590ba11dSSascha Wildner 	} else
1176590ba11dSSascha Wildner 		if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == NULL) {
1177590ba11dSSascha Wildner 			device_printf(sc->mfi_dev, "Mapping from MFI to MPT "
1178590ba11dSSascha Wildner 			    "Failed\n");
1179590ba11dSSascha Wildner 			return 1;
1180590ba11dSSascha Wildner 		}
1181590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_ILQP, (req_desc->words & 0xFFFFFFFF));
1182590ba11dSSascha Wildner 	MFI_WRITE4(sc, MFI_IHQP, (req_desc->words >>0x20));
1183590ba11dSSascha Wildner 
1184590ba11dSSascha Wildner 	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
1185590ba11dSSascha Wildner 		return 0;
1186590ba11dSSascha Wildner 
1187590ba11dSSascha Wildner 	/* This is a polled command, so busy-wait for it to complete. */
1188590ba11dSSascha Wildner 	while (hdr->cmd_status == 0xff) {
1189590ba11dSSascha Wildner 		DELAY(1000);
1190590ba11dSSascha Wildner 		tm -= 1;
1191590ba11dSSascha Wildner 		if (tm <= 0)
1192590ba11dSSascha Wildner 			break;
1193590ba11dSSascha Wildner 	}
1194590ba11dSSascha Wildner 
1195590ba11dSSascha Wildner 	if (hdr->cmd_status == 0xff) {
1196590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "Frame %p timed out "
1197590ba11dSSascha Wildner 		      "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
1198590ba11dSSascha Wildner 		return (ETIMEDOUT);
1199590ba11dSSascha Wildner 	}
1200590ba11dSSascha Wildner 	return 0;
1201590ba11dSSascha Wildner }
1202590ba11dSSascha Wildner 
mfi_issue_pending_cmds_again(struct mfi_softc * sc)1203590ba11dSSascha Wildner static void mfi_issue_pending_cmds_again (struct mfi_softc *sc)
1204590ba11dSSascha Wildner {
1205590ba11dSSascha Wildner 	struct mfi_command *cm, *tmp;
1206590ba11dSSascha Wildner 
1207148e9c0bSSascha Wildner 	mfi_lockassert(&sc->mfi_io_lock);
1208590ba11dSSascha Wildner 	TAILQ_FOREACH_REVERSE_MUTABLE(cm, &sc->mfi_busy, BUSYQ, cm_link, tmp) {
1209590ba11dSSascha Wildner 
1210590ba11dSSascha Wildner 		cm->retry_for_fw_reset++;
1211590ba11dSSascha Wildner 
1212590ba11dSSascha Wildner 		/*
1213590ba11dSSascha Wildner 		 * If a command has continuously been tried multiple times
1214590ba11dSSascha Wildner 		 * and causing a FW reset condition, no further recoveries
1215590ba11dSSascha Wildner 		 * should be performed on the controller
1216590ba11dSSascha Wildner 		 */
1217590ba11dSSascha Wildner 		if (cm->retry_for_fw_reset == 3) {
1218590ba11dSSascha Wildner 			device_printf(sc->mfi_dev, "megaraid_sas: command %d "
1219590ba11dSSascha Wildner 			    "was tried multiple times during adapter reset"
1220590ba11dSSascha Wildner 			    "Shutting down the HBA\n", cm->cm_index);
1221590ba11dSSascha Wildner 			mfi_kill_hba(sc);
1222590ba11dSSascha Wildner 			sc->hw_crit_error = 1;
1223590ba11dSSascha Wildner 			return;
1224590ba11dSSascha Wildner 		}
1225590ba11dSSascha Wildner 
1226590ba11dSSascha Wildner 		if ((cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0) {
1227590ba11dSSascha Wildner 			struct mfi_cmd_tbolt *cmd;
1228590ba11dSSascha Wildner 			mfi_remove_busy(cm);
1229590ba11dSSascha Wildner 			cmd = sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames -
1230590ba11dSSascha Wildner 			    1 ];
1231590ba11dSSascha Wildner 			mfi_tbolt_return_cmd(sc, cmd);
1232590ba11dSSascha Wildner 			if ((cm->cm_flags & MFI_ON_MFIQ_MASK) == 0) {
1233590ba11dSSascha Wildner 				if (cm->cm_frame->dcmd.opcode !=
1234590ba11dSSascha Wildner 				    MFI_DCMD_CTRL_EVENT_WAIT) {
1235590ba11dSSascha Wildner 					device_printf(sc->mfi_dev,
1236590ba11dSSascha Wildner 					    "APJ ****requeue command %d \n",
1237590ba11dSSascha Wildner 					    cm->cm_index);
1238590ba11dSSascha Wildner 					mfi_requeue_ready(cm);
1239590ba11dSSascha Wildner 				}
1240590ba11dSSascha Wildner 			}
1241590ba11dSSascha Wildner 			else
1242590ba11dSSascha Wildner 				mfi_release_command(cm);
1243590ba11dSSascha Wildner 		}
1244590ba11dSSascha Wildner 	}
1245590ba11dSSascha Wildner 	mfi_startio(sc);
1246590ba11dSSascha Wildner }
1247590ba11dSSascha Wildner 
mfi_kill_hba(struct mfi_softc * sc)1248590ba11dSSascha Wildner static void mfi_kill_hba (struct mfi_softc *sc)
1249590ba11dSSascha Wildner {
1250590ba11dSSascha Wildner 	if (sc->mfi_flags & MFI_FLAGS_TBOLT)
1251590ba11dSSascha Wildner 		MFI_WRITE4 (sc, 0x00,MFI_STOP_ADP);
1252590ba11dSSascha Wildner 	else
1253590ba11dSSascha Wildner 		MFI_WRITE4 (sc, MFI_IDB,MFI_STOP_ADP);
1254590ba11dSSascha Wildner }
1255590ba11dSSascha Wildner 
mfi_process_fw_state_chg_isr(void * arg)1256590ba11dSSascha Wildner static void mfi_process_fw_state_chg_isr(void *arg)
1257590ba11dSSascha Wildner {
1258590ba11dSSascha Wildner 	struct mfi_softc *sc= (struct mfi_softc *)arg;
1259590ba11dSSascha Wildner 	struct mfi_cmd_tbolt *cmd;
1260590ba11dSSascha Wildner 	int error, status;
1261590ba11dSSascha Wildner 
1262590ba11dSSascha Wildner 	if (sc->adpreset == 1) {
1263590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "First stage of FW reset "
1264590ba11dSSascha Wildner 		     "initiated...\n");
1265590ba11dSSascha Wildner 
1266590ba11dSSascha Wildner 		sc->mfi_adp_reset(sc);
1267590ba11dSSascha Wildner 		sc->mfi_enable_intr(sc);
1268590ba11dSSascha Wildner 
1269590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "First stage of reset complete, "
1270590ba11dSSascha Wildner 		    "second stage initiated...\n");
1271590ba11dSSascha Wildner 
1272590ba11dSSascha Wildner 		sc->adpreset = 2;
1273590ba11dSSascha Wildner 
1274590ba11dSSascha Wildner 		/* waiting for about 20 second before start the second init */
1275590ba11dSSascha Wildner 		for (int wait = 0; wait < 20000; wait++)
1276590ba11dSSascha Wildner 			DELAY(1000);
1277590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "Second stage of FW reset "
1278590ba11dSSascha Wildner 		     "initiated...\n");
1279590ba11dSSascha Wildner 		while ((status = MFI_READ4(sc, MFI_RSR)) & 0x04);
1280590ba11dSSascha Wildner 
1281590ba11dSSascha Wildner 		sc->mfi_disable_intr(sc);
1282590ba11dSSascha Wildner 
1283590ba11dSSascha Wildner 		/* We expect the FW state to be READY */
1284590ba11dSSascha Wildner 		if (mfi_transition_firmware(sc)) {
1285590ba11dSSascha Wildner 			device_printf(sc->mfi_dev, "controller is not in "
1286590ba11dSSascha Wildner 			    "ready state\n");
1287590ba11dSSascha Wildner 			mfi_kill_hba(sc);
1288590ba11dSSascha Wildner 			sc->hw_crit_error= 1;
1289590ba11dSSascha Wildner 			return ;
1290590ba11dSSascha Wildner 		}
1291590ba11dSSascha Wildner 		if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0)
1292590ba11dSSascha Wildner 				return;
1293590ba11dSSascha Wildner 
1294590ba11dSSascha Wildner 		lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE);
1295590ba11dSSascha Wildner 
1296590ba11dSSascha Wildner 		sc->mfi_enable_intr(sc);
1297590ba11dSSascha Wildner 		sc->adpreset = 0;
1298590ba11dSSascha Wildner 		kfree(sc->mfi_aen_cm->cm_data, M_MFIBUF);
1299590ba11dSSascha Wildner 		mfi_remove_busy(sc->mfi_aen_cm);
1300590ba11dSSascha Wildner 		cmd = sc->mfi_cmd_pool_tbolt[sc->mfi_aen_cm->cm_extra_frames
1301590ba11dSSascha Wildner 		    - 1];
1302590ba11dSSascha Wildner 		mfi_tbolt_return_cmd(sc, cmd);
1303590ba11dSSascha Wildner 		if (sc->mfi_aen_cm) {
1304590ba11dSSascha Wildner 			mfi_release_command(sc->mfi_aen_cm);
1305590ba11dSSascha Wildner 			sc->mfi_aen_cm = NULL;
1306590ba11dSSascha Wildner 		}
1307590ba11dSSascha Wildner 		if (sc->map_update_cmd) {
1308590ba11dSSascha Wildner 			mfi_release_command(sc->map_update_cmd);
1309590ba11dSSascha Wildner 			sc->map_update_cmd = NULL;
1310590ba11dSSascha Wildner 		}
1311590ba11dSSascha Wildner 		mfi_issue_pending_cmds_again(sc);
1312590ba11dSSascha Wildner 
1313590ba11dSSascha Wildner 		/*
1314590ba11dSSascha Wildner 		 * Issue pending command can result in adapter being marked
1315590ba11dSSascha Wildner 		 * dead because of too many re-tries. Check for that
1316590ba11dSSascha Wildner 		 * condition before clearing the reset condition on the FW
1317590ba11dSSascha Wildner 		 */
1318590ba11dSSascha Wildner 		if (!sc->hw_crit_error) {
1319590ba11dSSascha Wildner 			/*
1320590ba11dSSascha Wildner 			 * Initiate AEN (Asynchronous Event Notification)
1321590ba11dSSascha Wildner 			 */
1322590ba11dSSascha Wildner 			mfi_aen_setup(sc, sc->last_seq_num);
1323590ba11dSSascha Wildner 			sc->issuepend_done = 1;
1324590ba11dSSascha Wildner 			device_printf(sc->mfi_dev, "second stage of reset "
1325590ba11dSSascha Wildner 			    "complete, FW is ready now.\n");
1326590ba11dSSascha Wildner 		} else {
1327590ba11dSSascha Wildner 			device_printf(sc->mfi_dev, "second stage of reset "
1328590ba11dSSascha Wildner 			     "never completed, hba was marked offline.\n");
1329590ba11dSSascha Wildner 		}
1330590ba11dSSascha Wildner 	} else {
1331590ba11dSSascha Wildner 		device_printf(sc->mfi_dev, "mfi_process_fw_state_chg_isr "
1332590ba11dSSascha Wildner 		    "called with unhandled value:%d\n", sc->adpreset);
1333590ba11dSSascha Wildner 	}
1334590ba11dSSascha Wildner 	lockmgr(&sc->mfi_io_lock, LK_RELEASE);
1335590ba11dSSascha Wildner }
1336