mfi_tbolt.c revision 237546
1227068Sambrisko /*-
2227068Sambrisko * Redistribution and use in source and binary forms, with or without
3227068Sambrisko * modification, are permitted provided that the following conditions
4227068Sambrisko * are met:
5227068Sambrisko *
6227068Sambrisko *            Copyright 1994-2009 The FreeBSD Project.
7227068Sambrisko *            All rights reserved.
8227068Sambrisko *
9227068Sambrisko * 1. Redistributions of source code must retain the above copyright
10227068Sambrisko *    notice, this list of conditions and the following disclaimer.
11227068Sambrisko * 2. Redistributions in binary form must reproduce the above copyright
12227068Sambrisko *    notice, this list of conditions and the following disclaimer in the
13227068Sambrisko *    documentation and/or other materials provided with the distribution.
14227068Sambrisko *
15227068Sambrisko *    THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND
16227068Sambrisko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17227068Sambrisko * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18227068Sambrisko * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FREEBSD PROJECT OR
19227068Sambrisko * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20227068Sambrisko * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21227068Sambrisko * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22227068Sambrisko * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY
23227068Sambrisko * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24227068Sambrisko * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25227068Sambrisko * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26227068Sambrisko *
27227068Sambrisko * The views and conclusions contained in the software and documentation
28227068Sambrisko * are those of the authors and should not be interpreted as representing
29227068Sambrisko * official policies,either expressed or implied, of the FreeBSD Project.
30227068Sambrisko */
31227068Sambrisko
32227068Sambrisko
33227068Sambrisko#include <sys/cdefs.h>
34233711Sambrisko__FBSDID("$FreeBSD: head/sys/dev/mfi/mfi_tbolt.c 237546 2012-06-25 05:41:16Z kevlo $");
35227068Sambrisko
36227068Sambrisko#include "opt_mfi.h"
37227068Sambrisko
38227068Sambrisko#include <sys/param.h>
39227068Sambrisko#include <sys/types.h>
40227068Sambrisko#include <sys/kernel.h>
41227068Sambrisko#include <sys/selinfo.h>
42227068Sambrisko#include <sys/bus.h>
43227068Sambrisko#include <sys/conf.h>
44227068Sambrisko#include <sys/bio.h>
45227068Sambrisko#include <sys/ioccom.h>
46227068Sambrisko#include <sys/eventhandler.h>
47227068Sambrisko#include <sys/callout.h>
48227068Sambrisko#include <sys/uio.h>
49227068Sambrisko#include <machine/bus.h>
50233711Sambrisko#include <sys/sysctl.h>
51227068Sambrisko#include <sys/systm.h>
52227068Sambrisko#include <sys/malloc.h>
53227068Sambrisko
54227068Sambrisko#include <dev/mfi/mfireg.h>
55227068Sambrisko#include <dev/mfi/mfi_ioctl.h>
56227068Sambrisko#include <dev/mfi/mfivar.h>
57227068Sambrisko
58227068Sambriskostruct mfi_cmd_tbolt *mfi_tbolt_get_cmd(struct mfi_softc *sc);
59227068Sambriskounion mfi_mpi2_request_descriptor *
60227068Sambriskomfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index);
61227068Sambriskovoid mfi_tbolt_complete_cmd(struct mfi_softc *sc);
62227068Sambriskoint mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
63227068Sambrisko    struct mfi_cmd_tbolt *cmd);
64227068Sambriskostatic inline void mfi_tbolt_return_cmd(struct mfi_softc *sc,
65227068Sambrisko    struct mfi_cmd_tbolt *cmd);
66227068Sambriskounion mfi_mpi2_request_descriptor *mfi_tbolt_build_mpt_cmd(struct mfi_softc
67227068Sambrisko    *sc, struct mfi_command *cmd);
68227068Sambriskouint8_t
69227068Sambriskomfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd);
70227068Sambriskounion mfi_mpi2_request_descriptor *mfi_build_and_issue_cmd(struct mfi_softc
71227068Sambrisko    *sc, struct mfi_command *mfi_cmd);
72227068Sambriskoint mfi_tbolt_is_ldio(struct mfi_command *mfi_cmd);
73227068Sambriskovoid mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
74227068Sambrisko    struct mfi_cmd_tbolt *cmd);
75227068Sambriskostatic int mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command
76227068Sambrisko    *mfi_cmd, pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd);
77227068Sambriskostatic int mfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command
78227068Sambrisko    *mfi_cmd, uint8_t *cdb);
79227068Sambriskovoid
80227068Sambriskomap_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status,
81227068Sambrisko     uint8_t ext_status);
82227068Sambriskostatic void mfi_issue_pending_cmds_again (struct mfi_softc *sc);
83227068Sambriskostatic void mfi_kill_hba (struct mfi_softc *sc);
84227068Sambriskostatic void mfi_process_fw_state_chg_isr(void *arg);
85235014Sambriskostatic void mfi_sync_map_complete(struct mfi_command *);
86235014Sambriskostatic void mfi_queue_map_sync(struct mfi_softc *sc);
87227068Sambrisko
88227068Sambrisko#define MFI_FUSION_ENABLE_INTERRUPT_MASK	(0x00000008)
89227068Sambrisko
90227068Sambriskovoid
91227068Sambriskomfi_tbolt_enable_intr_ppc(struct mfi_softc *sc)
92227068Sambrisko{
93227068Sambrisko	MFI_WRITE4(sc, MFI_OMSK, ~MFI_FUSION_ENABLE_INTERRUPT_MASK);
94227068Sambrisko	MFI_READ4(sc, MFI_OMSK);
95227068Sambrisko}
96227068Sambrisko
97227068Sambriskovoid
98227068Sambriskomfi_tbolt_disable_intr_ppc(struct mfi_softc *sc)
99227068Sambrisko{
100227068Sambrisko	MFI_WRITE4(sc, MFI_OMSK, 0xFFFFFFFF);
101227068Sambrisko	MFI_READ4(sc, MFI_OMSK);
102227068Sambrisko}
103227068Sambrisko
104227068Sambriskoint32_t
105227068Sambriskomfi_tbolt_read_fw_status_ppc(struct mfi_softc *sc)
106227068Sambrisko{
107227068Sambrisko	return MFI_READ4(sc, MFI_OSP0);
108227068Sambrisko}
109227068Sambrisko
110227068Sambriskoint32_t
111227068Sambriskomfi_tbolt_check_clear_intr_ppc(struct mfi_softc *sc)
112227068Sambrisko{
113227068Sambrisko	int32_t status, mfi_status = 0;
114227068Sambrisko
115227068Sambrisko	status = MFI_READ4(sc, MFI_OSTS);
116227068Sambrisko
117233711Sambrisko	if (status & 1) {
118227068Sambrisko		MFI_WRITE4(sc, MFI_OSTS, status);
119227068Sambrisko		MFI_READ4(sc, MFI_OSTS);
120233711Sambrisko		if (status & MFI_STATE_CHANGE_INTERRUPT) {
121227068Sambrisko			mfi_status |= MFI_FIRMWARE_STATE_CHANGE;
122227068Sambrisko		}
123227068Sambrisko
124227068Sambrisko		return mfi_status;
125227068Sambrisko	}
126233711Sambrisko	if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
127227068Sambrisko		return 1;
128227068Sambrisko
129227068Sambrisko	MFI_READ4(sc, MFI_OSTS);
130227068Sambrisko	return 0;
131227068Sambrisko}
132227068Sambrisko
133227068Sambrisko
134227068Sambriskovoid
135233711Sambriskomfi_tbolt_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add,
136227068Sambrisko   uint32_t frame_cnt)
137227068Sambrisko{
138227068Sambrisko	bus_add |= (MFI_REQ_DESCRIPT_FLAGS_MFA
139227068Sambrisko	    << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
140233711Sambrisko	MFI_WRITE4(sc, MFI_IQPL, (uint32_t)bus_add);
141233711Sambrisko	MFI_WRITE4(sc, MFI_IQPH, (uint32_t)((uint64_t)bus_add >> 32));
142227068Sambrisko}
143227068Sambrisko
144235016Sambrisko/*
145227068Sambrisko * mfi_tbolt_adp_reset - For controller reset
146227068Sambrisko * @regs: MFI register set
147227068Sambrisko */
148235016Sambriskoint
149235016Sambriskomfi_tbolt_adp_reset(struct mfi_softc *sc)
150227068Sambrisko{
151233711Sambrisko	int retry = 0, i = 0;
152233711Sambrisko	int HostDiag;
153227068Sambrisko
154233711Sambrisko	MFI_WRITE4(sc, MFI_WSR, 0xF);
155233711Sambrisko	MFI_WRITE4(sc, MFI_WSR, 4);
156233711Sambrisko	MFI_WRITE4(sc, MFI_WSR, 0xB);
157233711Sambrisko	MFI_WRITE4(sc, MFI_WSR, 2);
158233711Sambrisko	MFI_WRITE4(sc, MFI_WSR, 7);
159233711Sambrisko	MFI_WRITE4(sc, MFI_WSR, 0xD);
160227068Sambrisko
161233711Sambrisko	for (i = 0; i < 10000; i++) ;
162227068Sambrisko
163233711Sambrisko	HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR);
164227068Sambrisko
165233711Sambrisko	while (!( HostDiag & DIAG_WRITE_ENABLE)) {
166233711Sambrisko		for (i = 0; i < 1000; i++);
167233711Sambrisko		HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR);
168233711Sambrisko		device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%x, "
169233711Sambrisko		    "hostdiag=%x\n", retry, HostDiag);
170227068Sambrisko
171233711Sambrisko		if (retry++ >= 100)
172233711Sambrisko			return 1;
173233711Sambrisko	}
174227068Sambrisko
175233711Sambrisko	device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: HostDiag=%x\n", HostDiag);
176227068Sambrisko
177233711Sambrisko	MFI_WRITE4(sc, MFI_HDR, (HostDiag | DIAG_RESET_ADAPTER));
178227068Sambrisko
179233711Sambrisko	for (i=0; i < 10; i++) {
180233711Sambrisko		for (i = 0; i < 10000; i++);
181233711Sambrisko	}
182227068Sambrisko
183233711Sambrisko	HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR);
184233711Sambrisko	while (HostDiag & DIAG_RESET_ADAPTER) {
185233711Sambrisko		for (i = 0; i < 1000; i++) ;
186233711Sambrisko		HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR);
187233711Sambrisko		device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%x, "
188233711Sambrisko		    "hostdiag=%x\n", retry, HostDiag);
189227068Sambrisko
190233711Sambrisko		if (retry++ >= 1000)
191233711Sambrisko			return 1;
192233711Sambrisko	}
193233711Sambrisko	return 0;
194227068Sambrisko}
195227068Sambrisko
196227068Sambrisko/*
197235016Sambrisko * This routine initialize Thunderbolt specific device information
198227068Sambrisko */
199235016Sambriskovoid
200235016Sambriskomfi_tbolt_init_globals(struct mfi_softc *sc)
201227068Sambrisko{
202227068Sambrisko	/* Initialize single reply size and Message size */
203227068Sambrisko	sc->reply_size = MEGASAS_THUNDERBOLT_REPLY_SIZE;
204227068Sambrisko	sc->raid_io_msg_size = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
205227068Sambrisko
206227068Sambrisko	/*
207227068Sambrisko	 * Calculating how many SGEs allowed in a allocated main message
208227068Sambrisko	 * (size of the Message - Raid SCSI IO message size(except SGE))
209227068Sambrisko	 * / size of SGE
210227068Sambrisko	 * (0x100 - (0x90 - 0x10)) / 0x10 = 8
211227068Sambrisko	 */
212227068Sambrisko	sc->max_SGEs_in_main_message =
213227068Sambrisko	    (uint8_t)((sc->raid_io_msg_size
214227068Sambrisko	    - (sizeof(struct mfi_mpi2_request_raid_scsi_io)
215227068Sambrisko	    - sizeof(MPI2_SGE_IO_UNION))) / sizeof(MPI2_SGE_IO_UNION));
216227068Sambrisko	/*
217227068Sambrisko	 * (Command frame size allocaed in SRB ext - Raid SCSI IO message size)
218227068Sambrisko	 * / size of SGL ;
219227068Sambrisko	 * (1280 - 256) / 16 = 64
220227068Sambrisko	 */
221227068Sambrisko	sc->max_SGEs_in_chain_message = (MR_COMMAND_SIZE
222227068Sambrisko	    - sc->raid_io_msg_size) / sizeof(MPI2_SGE_IO_UNION);
223227068Sambrisko	/*
224227068Sambrisko	 * (0x08-1) + 0x40 = 0x47 - 0x01 = 0x46  one is left for command
225227068Sambrisko	 * colscing
226227068Sambrisko	*/
227227068Sambrisko	sc->mfi_max_sge = (sc->max_SGEs_in_main_message - 1)
228227068Sambrisko	    + sc->max_SGEs_in_chain_message - 1;
229227068Sambrisko	/*
230227068Sambrisko	* This is the offset in number of 4 * 32bit words to the next chain
231227068Sambrisko	* (0x100 - 0x10)/0x10 = 0xF(15)
232227068Sambrisko	*/
233227068Sambrisko	sc->chain_offset_value_for_main_message = (sc->raid_io_msg_size
234227068Sambrisko	    - sizeof(MPI2_SGE_IO_UNION))/16;
235227068Sambrisko	sc->chain_offset_value_for_mpt_ptmsg
236227068Sambrisko	    = offsetof(struct mfi_mpi2_request_raid_scsi_io, SGL)/16;
237227068Sambrisko	sc->mfi_cmd_pool_tbolt = NULL;
238227068Sambrisko	sc->request_desc_pool = NULL;
239227068Sambrisko}
240227068Sambrisko
241227068Sambrisko/*
242235016Sambrisko * This function calculates the memory requirement for Thunderbolt
243235016Sambrisko * controller, returns the total required memory in bytes
244227068Sambrisko */
245227068Sambrisko
246235016Sambriskouint32_t
247235016Sambriskomfi_tbolt_get_memory_requirement(struct mfi_softc *sc)
248227068Sambrisko{
249227068Sambrisko	uint32_t size;
250233711Sambrisko	size = MEGASAS_THUNDERBOLT_MSG_ALLIGNMENT;	/* for Alignment */
251227068Sambrisko	size += sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1);
252227068Sambrisko	size += sc->reply_size * sc->mfi_max_fw_cmds;
253233711Sambrisko	/* this is for SGL's */
254227068Sambrisko	size += MEGASAS_MAX_SZ_CHAIN_FRAME * sc->mfi_max_fw_cmds;
255227068Sambrisko	return size;
256227068Sambrisko}
257227068Sambrisko
258227068Sambrisko/*
259227068Sambrisko * Description:
260227068Sambrisko *      This function will prepare message pools for the Thunderbolt controller
261227068Sambrisko * Arguments:
262227068Sambrisko *      DevExt - HBA miniport driver's adapter data storage structure
263227068Sambrisko *      pMemLocation - start of the memory allocated for Thunderbolt.
264227068Sambrisko * Return Value:
265227068Sambrisko *      TRUE if successful
266227068Sambrisko *      FALSE if failed
267227068Sambrisko */
268235016Sambriskoint
269235016Sambriskomfi_tbolt_init_desc_pool(struct mfi_softc *sc, uint8_t* mem_location,
270227068Sambrisko    uint32_t tbolt_contg_length)
271227068Sambrisko{
272227068Sambrisko	uint32_t     offset = 0;
273227068Sambrisko	uint8_t      *addr = mem_location;
274227068Sambrisko
275227068Sambrisko	/* Request Descriptor Base physical Address */
276227068Sambrisko
277227068Sambrisko	/* For Request Decriptors Virtual Memory */
278227068Sambrisko	/* Initialise the aligned IO Frames Virtual Memory Pointer */
279233711Sambrisko	if (((uintptr_t)addr) & (0xFF)) {
280227068Sambrisko		addr = &addr[sc->raid_io_msg_size];
281227068Sambrisko		addr = (uint8_t *)((uintptr_t)addr & (~0xFF));
282227068Sambrisko		sc->request_message_pool_align = addr;
283227068Sambrisko	} else
284227068Sambrisko		sc->request_message_pool_align = addr;
285227068Sambrisko
286227068Sambrisko	offset = sc->request_message_pool_align - sc->request_message_pool;
287227068Sambrisko	sc->request_msg_busaddr = sc->mfi_tb_busaddr + offset;
288227068Sambrisko
289227068Sambrisko	/* DJA XXX should this be bus dma ??? */
290227068Sambrisko	/* Skip request message pool */
291227068Sambrisko	addr = &addr[sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1)];
292227068Sambrisko	/* Reply Frame Pool is initialized */
293227068Sambrisko	sc->reply_frame_pool = (struct mfi_mpi2_reply_header *) addr;
294233711Sambrisko	if (((uintptr_t)addr) & (0xFF)) {
295227068Sambrisko		addr = &addr[sc->reply_size];
296227068Sambrisko		addr = (uint8_t *)((uintptr_t)addr & (~0xFF));
297227068Sambrisko	}
298227068Sambrisko	sc->reply_frame_pool_align
299227068Sambrisko		    = (struct mfi_mpi2_reply_header *)addr;
300227068Sambrisko
301227068Sambrisko	offset = (uintptr_t)sc->reply_frame_pool_align
302227068Sambrisko	    - (uintptr_t)sc->request_message_pool;
303227068Sambrisko	sc->reply_frame_busaddr = sc->mfi_tb_busaddr + offset;
304227068Sambrisko
305227068Sambrisko	/* Skip Reply Frame Pool */
306227068Sambrisko	addr += sc->reply_size * sc->mfi_max_fw_cmds;
307227068Sambrisko	sc->reply_pool_limit = addr;
308227068Sambrisko
309227068Sambrisko	/* initializing reply address to 0xFFFFFFFF */
310227068Sambrisko	memset((uint8_t *)sc->reply_frame_pool, 0xFF,
311227068Sambrisko	       (sc->reply_size * sc->mfi_max_fw_cmds));
312227068Sambrisko
313227068Sambrisko	offset = sc->reply_size * sc->mfi_max_fw_cmds;
314227068Sambrisko	sc->sg_frame_busaddr = sc->reply_frame_busaddr + offset;
315227068Sambrisko	/* initialize the last_reply_idx to 0 */
316227068Sambrisko	sc->last_reply_idx = 0;
317227068Sambrisko	offset = (sc->sg_frame_busaddr + (MEGASAS_MAX_SZ_CHAIN_FRAME *
318227068Sambrisko	    sc->mfi_max_fw_cmds)) - sc->mfi_tb_busaddr;
319233711Sambrisko	if (offset > tbolt_contg_length)
320233711Sambrisko		device_printf(sc->mfi_dev, "Error:Initialized more than "
321227068Sambrisko		    "allocated\n");
322227068Sambrisko	return 0;
323227068Sambrisko}
324227068Sambrisko
325227068Sambrisko/*
326235016Sambrisko * This routine prepare and issue INIT2 frame to the Firmware
327227068Sambrisko */
328227068Sambrisko
329227068Sambriskoint
330227068Sambriskomfi_tbolt_init_MFI_queue(struct mfi_softc *sc)
331227068Sambrisko{
332227068Sambrisko	struct MPI2_IOC_INIT_REQUEST   *mpi2IocInit;
333227068Sambrisko	struct mfi_init_frame	*mfi_init;
334227068Sambrisko	uintptr_t			offset = 0;
335233711Sambrisko	bus_addr_t			phyAddress;
336227068Sambrisko	MFI_ADDRESS			*mfiAddressTemp;
337227068Sambrisko	struct mfi_command *cm;
338227068Sambrisko	int error;
339227068Sambrisko
340227068Sambrisko	mpi2IocInit = (struct MPI2_IOC_INIT_REQUEST *)sc->mfi_tb_ioc_init_desc;
341227068Sambrisko	/* Check if initialization is already completed */
342233711Sambrisko	if (sc->MFA_enabled) {
343227068Sambrisko		return 1;
344227068Sambrisko	}
345227068Sambrisko
346227068Sambrisko	mtx_lock(&sc->mfi_io_lock);
347227068Sambrisko	if ((cm = mfi_dequeue_free(sc)) == NULL) {
348227068Sambrisko		mtx_unlock(&sc->mfi_io_lock);
349227068Sambrisko		return (EBUSY);
350227068Sambrisko	}
351227068Sambrisko	cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_tb_init);
352227068Sambrisko	cm->cm_frame_busaddr = sc->mfi_tb_init_busaddr;
353227068Sambrisko	cm->cm_dmamap = sc->mfi_tb_init_dmamap;
354227068Sambrisko	cm->cm_frame->header.context = 0;
355227068Sambrisko	cm->cm_sc = sc;
356227068Sambrisko	cm->cm_index = 0;
357227068Sambrisko
358227068Sambrisko	/*
359227068Sambrisko	 * Abuse the SG list area of the frame to hold the init_qinfo
360227068Sambrisko	 * object;
361227068Sambrisko	 */
362227068Sambrisko	mfi_init = &cm->cm_frame->init;
363227068Sambrisko
364227068Sambrisko	bzero(mpi2IocInit, sizeof(struct MPI2_IOC_INIT_REQUEST));
365227068Sambrisko	mpi2IocInit->Function  = MPI2_FUNCTION_IOC_INIT;
366227068Sambrisko	mpi2IocInit->WhoInit   = MPI2_WHOINIT_HOST_DRIVER;
367227068Sambrisko
368227068Sambrisko	/* set MsgVersion and HeaderVersion host driver was built with */
369227068Sambrisko	mpi2IocInit->MsgVersion = MPI2_VERSION;
370227068Sambrisko	mpi2IocInit->HeaderVersion = MPI2_HEADER_VERSION;
371227068Sambrisko	mpi2IocInit->SystemRequestFrameSize = sc->raid_io_msg_size/4;
372227068Sambrisko	mpi2IocInit->ReplyDescriptorPostQueueDepth
373227068Sambrisko	    = (uint16_t)sc->mfi_max_fw_cmds;
374227068Sambrisko	mpi2IocInit->ReplyFreeQueueDepth = 0; /* Not supported by MR. */
375227068Sambrisko
376227068Sambrisko	/* Get physical address of reply frame pool */
377227068Sambrisko	offset = (uintptr_t) sc->reply_frame_pool_align
378227068Sambrisko	    - (uintptr_t)sc->request_message_pool;
379227068Sambrisko	phyAddress = sc->mfi_tb_busaddr + offset;
380227068Sambrisko	mfiAddressTemp =
381227068Sambrisko	    (MFI_ADDRESS *)&mpi2IocInit->ReplyDescriptorPostQueueAddress;
382233711Sambrisko	mfiAddressTemp->u.addressLow = (uint32_t)phyAddress;
383233711Sambrisko	mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32);
384227068Sambrisko
385227068Sambrisko	/* Get physical address of request message pool */
386227068Sambrisko	offset = sc->request_message_pool_align - sc->request_message_pool;
387227068Sambrisko	phyAddress =  sc->mfi_tb_busaddr + offset;
388227068Sambrisko	mfiAddressTemp = (MFI_ADDRESS *)&mpi2IocInit->SystemRequestFrameBaseAddress;
389233711Sambrisko	mfiAddressTemp->u.addressLow = (uint32_t)phyAddress;
390233711Sambrisko	mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32);
391233711Sambrisko	mpi2IocInit->ReplyFreeQueueAddress =  0; /* Not supported by MR. */
392227068Sambrisko	mpi2IocInit->TimeStamp = time_uptime;
393227068Sambrisko
394227068Sambrisko	if (sc->verbuf) {
395227068Sambrisko		snprintf((char *)sc->verbuf, strlen(MEGASAS_VERSION) + 2, "%s\n",
396227068Sambrisko                MEGASAS_VERSION);
397233711Sambrisko		mfi_init->driver_ver_lo = (uint32_t)sc->verbuf_h_busaddr;
398233711Sambrisko		mfi_init->driver_ver_hi =
399233711Sambrisko		    (uint32_t)((uint64_t)sc->verbuf_h_busaddr >> 32);
400227068Sambrisko	}
401227068Sambrisko	/* Get the physical address of the mpi2 ioc init command */
402227068Sambrisko	phyAddress =  sc->mfi_tb_ioc_init_busaddr;
403233711Sambrisko	mfi_init->qinfo_new_addr_lo = (uint32_t)phyAddress;
404233711Sambrisko	mfi_init->qinfo_new_addr_hi = (uint32_t)((uint64_t)phyAddress >> 32);
405227068Sambrisko	mfi_init->header.flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
406227068Sambrisko
407227068Sambrisko	mfi_init->header.cmd = MFI_CMD_INIT;
408227068Sambrisko	mfi_init->header.data_len = sizeof(struct MPI2_IOC_INIT_REQUEST);
409227068Sambrisko	mfi_init->header.cmd_status = MFI_STAT_INVALID_STATUS;
410227068Sambrisko
411227068Sambrisko	cm->cm_data = NULL;
412227068Sambrisko	cm->cm_flags |= MFI_CMD_POLLED;
413227068Sambrisko	cm->cm_timestamp = time_uptime;
414227068Sambrisko	if ((error = mfi_mapcmd(sc, cm)) != 0) {
415227068Sambrisko		device_printf(sc->mfi_dev, "failed to send IOC init2 "
416227068Sambrisko		    "command %d at %lx\n", error, (long)cm->cm_frame_busaddr);
417227068Sambrisko		mfi_release_command(cm);
418227068Sambrisko		mtx_unlock(&sc->mfi_io_lock);
419227068Sambrisko		return (error);
420227068Sambrisko	}
421227068Sambrisko	mfi_release_command(cm);
422227068Sambrisko	mtx_unlock(&sc->mfi_io_lock);
423227068Sambrisko
424233711Sambrisko	if (mfi_init->header.cmd_status == 0) {
425227068Sambrisko		sc->MFA_enabled = 1;
426227068Sambrisko	}
427227068Sambrisko	else {
428227068Sambrisko		device_printf(sc->mfi_dev, "Init command Failed %x\n",
429227068Sambrisko		    mfi_init->header.cmd_status);
430227068Sambrisko		return 1;
431227068Sambrisko	}
432227068Sambrisko
433227068Sambrisko	return 0;
434227068Sambrisko
435227068Sambrisko}
436227068Sambrisko
437235016Sambriskoint
438235016Sambriskomfi_tbolt_alloc_cmd(struct mfi_softc *sc)
439227068Sambrisko{
440227068Sambrisko	struct mfi_cmd_tbolt *cmd;
441233711Sambrisko	bus_addr_t io_req_base_phys;
442227068Sambrisko	uint8_t *io_req_base;
443233711Sambrisko	int i = 0, j = 0, offset = 0;
444227068Sambrisko
445227068Sambrisko	/*
446227068Sambrisko	 * sc->mfi_cmd_pool_tbolt is an array of struct mfi_cmd_tbolt pointers.
447227068Sambrisko	 * Allocate the dynamic array first and then allocate individual
448227068Sambrisko	 * commands.
449227068Sambrisko	 */
450227068Sambrisko	sc->request_desc_pool = malloc(sizeof(
451227068Sambrisko	    union mfi_mpi2_request_descriptor) * sc->mfi_max_fw_cmds,
452227068Sambrisko	    M_MFIBUF, M_NOWAIT|M_ZERO);
453227068Sambrisko	sc->mfi_cmd_pool_tbolt = malloc(sizeof(struct mfi_cmd_tbolt*)
454227068Sambrisko	    * sc->mfi_max_fw_cmds, M_MFIBUF, M_NOWAIT|M_ZERO);
455227068Sambrisko
456227068Sambrisko	if (!sc->mfi_cmd_pool_tbolt) {
457227068Sambrisko		device_printf(sc->mfi_dev, "out of memory. Could not alloc "
458227068Sambrisko		    "memory for cmd_list_fusion\n");
459227068Sambrisko		return 1;
460227068Sambrisko	}
461227068Sambrisko
462227068Sambrisko	for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
463227068Sambrisko		sc->mfi_cmd_pool_tbolt[i] = malloc(sizeof(
464227068Sambrisko		    struct mfi_cmd_tbolt),M_MFIBUF, M_NOWAIT|M_ZERO);
465227068Sambrisko
466227068Sambrisko		if (!sc->mfi_cmd_pool_tbolt[i]) {
467227068Sambrisko			device_printf(sc->mfi_dev, "Could not alloc cmd list "
468227068Sambrisko			    "fusion\n");
469227068Sambrisko
470227068Sambrisko			for (j = 0; j < i; j++)
471227068Sambrisko				free(sc->mfi_cmd_pool_tbolt[j], M_MFIBUF);
472227068Sambrisko
473227068Sambrisko			free(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
474227068Sambrisko			sc->mfi_cmd_pool_tbolt = NULL;
475227068Sambrisko		}
476227068Sambrisko	}
477227068Sambrisko
478227068Sambrisko	/*
479227068Sambrisko	 * The first 256 bytes (SMID 0) is not used. Don't add to the cmd
480227068Sambrisko	 *list
481227068Sambrisko	 */
482227068Sambrisko	io_req_base = sc->request_message_pool_align
483227068Sambrisko		+ MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
484227068Sambrisko	io_req_base_phys = sc->request_msg_busaddr
485227068Sambrisko		+ MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
486227068Sambrisko
487227068Sambrisko	/*
488227068Sambrisko	 * Add all the commands to command pool (instance->cmd_pool)
489227068Sambrisko	 */
490227068Sambrisko	/* SMID 0 is reserved. Set SMID/index from 1 */
491227068Sambrisko
492227068Sambrisko	for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
493227068Sambrisko		cmd = sc->mfi_cmd_pool_tbolt[i];
494227068Sambrisko		offset = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * i;
495227068Sambrisko		cmd->index = i + 1;
496227068Sambrisko		cmd->request_desc = (union mfi_mpi2_request_descriptor *)
497227068Sambrisko		    (sc->request_desc_pool + i);
498227068Sambrisko		cmd->io_request = (struct mfi_mpi2_request_raid_scsi_io *)
499227068Sambrisko		    (io_req_base + offset);
500227068Sambrisko		cmd->io_request_phys_addr = io_req_base_phys + offset;
501227068Sambrisko		cmd->sg_frame = (MPI2_SGE_IO_UNION *)(sc->reply_pool_limit
502227068Sambrisko		    + i * MEGASAS_MAX_SZ_CHAIN_FRAME);
503227068Sambrisko		cmd->sg_frame_phys_addr = sc->sg_frame_busaddr + i
504227068Sambrisko		    * MEGASAS_MAX_SZ_CHAIN_FRAME;
505227068Sambrisko
506227068Sambrisko		TAILQ_INSERT_TAIL(&(sc->mfi_cmd_tbolt_tqh), cmd, next);
507227068Sambrisko	}
508227068Sambrisko	return 0;
509227068Sambrisko}
510227068Sambrisko
511235016Sambriskoint
512235016Sambriskomfi_tbolt_reset(struct mfi_softc *sc)
513227068Sambrisko{
514227068Sambrisko	uint32_t fw_state;
515227068Sambrisko
516227068Sambrisko	mtx_lock(&sc->mfi_io_lock);
517233711Sambrisko	if (sc->hw_crit_error) {
518233711Sambrisko		device_printf(sc->mfi_dev, "HW CRITICAL ERROR\n");
519227068Sambrisko		mtx_unlock(&sc->mfi_io_lock);
520227068Sambrisko		return 1;
521227068Sambrisko	}
522227068Sambrisko
523233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
524227068Sambrisko		fw_state = sc->mfi_read_fw_status(sc);
525233711Sambrisko		if ((fw_state & MFI_FWSTATE_FAULT) == MFI_FWSTATE_FAULT) {
526233711Sambrisko			if ((sc->disableOnlineCtrlReset == 0)
527233711Sambrisko			    && (sc->adpreset == 0)) {
528233711Sambrisko				device_printf(sc->mfi_dev, "Adapter RESET "
529227068Sambrisko				    "condition is detected\n");
530227068Sambrisko				sc->adpreset = 1;
531227068Sambrisko				sc->issuepend_done = 0;
532227068Sambrisko				sc->MFA_enabled = 0;
533227068Sambrisko				sc->last_reply_idx = 0;
534227068Sambrisko				mfi_process_fw_state_chg_isr((void *) sc);
535227068Sambrisko			}
536227068Sambrisko			mtx_unlock(&sc->mfi_io_lock);
537227068Sambrisko			return 0;
538227068Sambrisko		}
539227068Sambrisko	}
540227068Sambrisko	mtx_unlock(&sc->mfi_io_lock);
541227068Sambrisko	return 1;
542227068Sambrisko}
543227068Sambrisko
544227068Sambrisko/*
545227068Sambrisko * mfi_intr_tbolt - isr entry point
546227068Sambrisko */
547235016Sambriskovoid
548235016Sambriskomfi_intr_tbolt(void *arg)
549227068Sambrisko{
550227068Sambrisko	struct mfi_softc *sc = (struct mfi_softc *)arg;
551227068Sambrisko
552233711Sambrisko	if (sc->mfi_check_clear_intr(sc) == 1) {
553227068Sambrisko		return;
554227068Sambrisko	}
555233711Sambrisko	if (sc->mfi_detaching)
556227068Sambrisko		return;
557227068Sambrisko	mtx_lock(&sc->mfi_io_lock);
558227068Sambrisko	mfi_tbolt_complete_cmd(sc);
559233711Sambrisko	if (sc->mfi_flags & MFI_FLAGS_QFRZN)
560227068Sambrisko		sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
561227068Sambrisko	mfi_startio(sc);
562227068Sambrisko	mtx_unlock(&sc->mfi_io_lock);
563227068Sambrisko	return;
564227068Sambrisko}
565227068Sambrisko
566235016Sambrisko/*
567227068Sambrisko * map_cmd_status -	Maps FW cmd status to OS cmd status
568227068Sambrisko * @cmd :		Pointer to cmd
569227068Sambrisko * @status :		status of cmd returned by FW
570227068Sambrisko * @ext_status :	ext status of cmd returned by FW
571227068Sambrisko */
572227068Sambrisko
573227068Sambriskovoid
574227068Sambriskomap_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status,
575227068Sambrisko    uint8_t ext_status)
576227068Sambrisko{
577227068Sambrisko
578227068Sambrisko	switch (status) {
579227068Sambrisko		case MFI_STAT_OK:
580227068Sambrisko			mfi_cmd->cm_frame->header.cmd_status = 0;
581227068Sambrisko			mfi_cmd->cm_frame->dcmd.header.cmd_status = 0;
582227068Sambrisko			break;
583227068Sambrisko
584227068Sambrisko		case MFI_STAT_SCSI_IO_FAILED:
585227068Sambrisko		case MFI_STAT_LD_INIT_IN_PROGRESS:
586227068Sambrisko			mfi_cmd->cm_frame->header.cmd_status = status;
587227068Sambrisko			mfi_cmd->cm_frame->header.scsi_status = ext_status;
588227068Sambrisko			mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
589227068Sambrisko			mfi_cmd->cm_frame->dcmd.header.scsi_status
590227068Sambrisko			    = ext_status;
591227068Sambrisko			break;
592227068Sambrisko
593227068Sambrisko		case MFI_STAT_SCSI_DONE_WITH_ERROR:
594227068Sambrisko			mfi_cmd->cm_frame->header.cmd_status = ext_status;
595227068Sambrisko			mfi_cmd->cm_frame->dcmd.header.cmd_status = ext_status;
596227068Sambrisko			break;
597227068Sambrisko
598227068Sambrisko		case MFI_STAT_LD_OFFLINE:
599227068Sambrisko		case MFI_STAT_DEVICE_NOT_FOUND:
600227068Sambrisko			mfi_cmd->cm_frame->header.cmd_status = status;
601227068Sambrisko			mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
602227068Sambrisko			break;
603227068Sambrisko
604227068Sambrisko		default:
605227068Sambrisko			mfi_cmd->cm_frame->header.cmd_status = status;
606227068Sambrisko			mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
607227068Sambrisko			break;
608227068Sambrisko		}
609227068Sambrisko}
610227068Sambrisko
611235016Sambrisko/*
612233711Sambrisko * mfi_tbolt_return_cmd -	Return a cmd to free command pool
613233711Sambrisko * @instance:		Adapter soft state
614233711Sambrisko * @cmd:		Command packet to be returned to free command pool
615233711Sambrisko */
616233711Sambriskostatic inline void
617233711Sambriskomfi_tbolt_return_cmd(struct mfi_softc *sc, struct mfi_cmd_tbolt *cmd)
618233711Sambrisko{
619233711Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
620227068Sambrisko
621233711Sambrisko	TAILQ_INSERT_TAIL(&sc->mfi_cmd_tbolt_tqh, cmd, next);
622233711Sambrisko}
623227068Sambrisko
624235014Sambriskovoid
625235014Sambriskomfi_tbolt_complete_cmd(struct mfi_softc *sc)
626227068Sambrisko{
627227068Sambrisko	struct mfi_mpi2_reply_header *desc, *reply_desc;
628235014Sambrisko	struct mfi_command *cmd_mfi, *cmd_mfi_check;	/* For MFA Cmds */
629227068Sambrisko	struct mfi_cmd_tbolt *cmd_tbolt;
630227068Sambrisko	uint16_t smid;
631227068Sambrisko	uint8_t reply_descript_type;
632227068Sambrisko	struct mfi_mpi2_request_raid_scsi_io  *scsi_io_req;
633227068Sambrisko	uint32_t status, extStatus;
634227068Sambrisko	uint16_t num_completed;
635227068Sambrisko	union desc_value val;
636227068Sambrisko
637227068Sambrisko	desc = (struct mfi_mpi2_reply_header *)
638227068Sambrisko		((uintptr_t)sc->reply_frame_pool_align
639227068Sambrisko		+ sc->last_reply_idx * sc->reply_size);
640227068Sambrisko	reply_desc = desc;
641227068Sambrisko
642227068Sambrisko	if (!reply_desc)
643227068Sambrisko		device_printf(sc->mfi_dev, "reply desc is NULL!!\n");
644227068Sambrisko
645227068Sambrisko	reply_descript_type = reply_desc->ReplyFlags
646227068Sambrisko	     & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
647227068Sambrisko	if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
648227068Sambrisko		return;
649227068Sambrisko
650227068Sambrisko	num_completed = 0;
651227068Sambrisko	val.word = ((union mfi_mpi2_reply_descriptor *)desc)->words;
652227068Sambrisko
653227068Sambrisko	/* Read Reply descriptor */
654227068Sambrisko	while ((val.u.low != 0xFFFFFFFF) && (val.u.high != 0xFFFFFFFF)) {
655227068Sambrisko		smid = reply_desc->SMID;
656227068Sambrisko		if (!smid || smid > sc->mfi_max_fw_cmds + 1) {
657227068Sambrisko			device_printf(sc->mfi_dev, "smid is %x. Cannot "
658233711Sambrisko			    "proceed. Returning \n", smid);
659227068Sambrisko			return;
660227068Sambrisko		}
661227068Sambrisko
662227068Sambrisko		cmd_tbolt = sc->mfi_cmd_pool_tbolt[smid - 1];
663227068Sambrisko		cmd_mfi = &sc->mfi_commands[cmd_tbolt->sync_cmd_idx];
664227068Sambrisko		scsi_io_req = cmd_tbolt->io_request;
665227068Sambrisko
666227068Sambrisko		status = cmd_mfi->cm_frame->dcmd.header.cmd_status;
667227068Sambrisko		extStatus = cmd_mfi->cm_frame->dcmd.header.scsi_status;
668235014Sambrisko		map_tbolt_cmd_status(cmd_mfi, status, extStatus);
669227068Sambrisko
670235014Sambrisko		/* remove command from busy queue if not polled */
671235014Sambrisko		TAILQ_FOREACH(cmd_mfi_check, &sc->mfi_busy, cm_link) {
672235014Sambrisko			if (cmd_mfi_check == cmd_mfi) {
673227068Sambrisko				mfi_remove_busy(cmd_mfi);
674235014Sambrisko				break;
675227068Sambrisko			}
676227068Sambrisko		}
677235014Sambrisko		cmd_mfi->cm_error = 0;
678235014Sambrisko		mfi_complete(sc, cmd_mfi);
679235014Sambrisko		mfi_tbolt_return_cmd(sc, cmd_tbolt);
680227068Sambrisko
681227068Sambrisko		sc->last_reply_idx++;
682227068Sambrisko		if (sc->last_reply_idx >= sc->mfi_max_fw_cmds) {
683227068Sambrisko			MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
684227068Sambrisko			sc->last_reply_idx = 0;
685227068Sambrisko		}
686227068Sambrisko		/*set it back to all 0xfff.*/
687227068Sambrisko		((union mfi_mpi2_reply_descriptor*)desc)->words =
688227068Sambrisko			~((uint64_t)0x00);
689227068Sambrisko
690227068Sambrisko		num_completed++;
691227068Sambrisko
692227068Sambrisko		/* Get the next reply descriptor */
693227068Sambrisko		desc = (struct mfi_mpi2_reply_header *)
694227068Sambrisko		    ((uintptr_t)sc->reply_frame_pool_align
695227068Sambrisko		    + sc->last_reply_idx * sc->reply_size);
696227068Sambrisko		reply_desc = desc;
697227068Sambrisko		val.word = ((union mfi_mpi2_reply_descriptor*)desc)->words;
698227068Sambrisko		reply_descript_type = reply_desc->ReplyFlags
699227068Sambrisko		    & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
700233711Sambrisko		if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
701227068Sambrisko			break;
702227068Sambrisko	}
703227068Sambrisko
704227068Sambrisko	if (!num_completed)
705227068Sambrisko		return;
706227068Sambrisko
707227068Sambrisko	/* update replyIndex to FW */
708233711Sambrisko	if (sc->last_reply_idx)
709227068Sambrisko		MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
710227068Sambrisko
711227068Sambrisko	return;
712227068Sambrisko}
713227068Sambrisko
714235016Sambrisko/*
715227068Sambrisko * mfi_get_cmd -	Get a command from the free pool
716227068Sambrisko * @instance:		Adapter soft state
717227068Sambrisko *
718227068Sambrisko * Returns a free command from the pool
719227068Sambrisko */
720227068Sambrisko
721235016Sambriskostruct mfi_cmd_tbolt *
722235016Sambriskomfi_tbolt_get_cmd(struct mfi_softc *sc)
723227068Sambrisko{
724227068Sambrisko	struct mfi_cmd_tbolt *cmd = NULL;
725227068Sambrisko
726227068Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
727227068Sambrisko
728227068Sambrisko	cmd = TAILQ_FIRST(&sc->mfi_cmd_tbolt_tqh);
729227068Sambrisko	TAILQ_REMOVE(&sc->mfi_cmd_tbolt_tqh, cmd, next);
730227068Sambrisko	memset((uint8_t *)cmd->sg_frame, 0, MEGASAS_MAX_SZ_CHAIN_FRAME);
731227068Sambrisko	memset((uint8_t *)cmd->io_request, 0,
732227068Sambrisko	    MEGASAS_THUNDERBOLT_NEW_MSG_SIZE);
733227068Sambrisko	return cmd;
734227068Sambrisko}
735227068Sambrisko
736227068Sambriskounion mfi_mpi2_request_descriptor *
737227068Sambriskomfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index)
738227068Sambrisko{
739227068Sambrisko	uint8_t *p;
740227068Sambrisko
741227068Sambrisko	if (index >= sc->mfi_max_fw_cmds) {
742227068Sambrisko		device_printf(sc->mfi_dev, "Invalid SMID (0x%x)request "
743227068Sambrisko		    "for descriptor\n", index);
744227068Sambrisko		return NULL;
745227068Sambrisko	}
746227068Sambrisko	p = sc->request_desc_pool + sizeof(union mfi_mpi2_request_descriptor)
747227068Sambrisko	    * index;
748227068Sambrisko	memset(p, 0, sizeof(union mfi_mpi2_request_descriptor));
749227068Sambrisko	return (union mfi_mpi2_request_descriptor *)p;
750227068Sambrisko}
751227068Sambrisko
752227068Sambrisko
753233711Sambrisko/* Used to build IOCTL cmd */
754227068Sambriskouint8_t
755227068Sambriskomfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd)
756227068Sambrisko{
757227068Sambrisko	MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain;
758227068Sambrisko	struct mfi_mpi2_request_raid_scsi_io *io_req;
759227068Sambrisko	struct mfi_cmd_tbolt *cmd;
760227068Sambrisko
761227068Sambrisko	cmd = mfi_tbolt_get_cmd(sc);
762227068Sambrisko	if (!cmd)
763227068Sambrisko		return EBUSY;
764233711Sambrisko	mfi_cmd->cm_extra_frames = cmd->index; /* Frame count used as SMID */
765227068Sambrisko	cmd->sync_cmd_idx = mfi_cmd->cm_index;
766227068Sambrisko	io_req = cmd->io_request;
767227068Sambrisko	mpi25_ieee_chain = (MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;
768227068Sambrisko
769227068Sambrisko	io_req->Function = MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
770227068Sambrisko	io_req->SGLOffset0 = offsetof(struct mfi_mpi2_request_raid_scsi_io,
771227068Sambrisko	    SGL) / 4;
772227068Sambrisko	io_req->ChainOffset = sc->chain_offset_value_for_mpt_ptmsg;
773227068Sambrisko
774227068Sambrisko	mpi25_ieee_chain->Address = mfi_cmd->cm_frame_busaddr;
775227068Sambrisko
776227068Sambrisko	/*
777227068Sambrisko	  In MFI pass thru, nextChainOffset will always be zero to
778227068Sambrisko	  indicate the end of the chain.
779227068Sambrisko	*/
780227068Sambrisko	mpi25_ieee_chain->Flags= MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT
781227068Sambrisko		| MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
782227068Sambrisko
783227068Sambrisko	/* setting the length to the maximum length */
784227068Sambrisko	mpi25_ieee_chain->Length = 1024;
785227068Sambrisko
786227068Sambrisko	return 0;
787227068Sambrisko}
788227068Sambrisko
789227068Sambriskovoid
790227068Sambriskomfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
791227068Sambrisko    struct mfi_cmd_tbolt *cmd)
792227068Sambrisko{
793227068Sambrisko	uint32_t start_lba_lo = 0, start_lba_hi = 0, device_id;
794227068Sambrisko	struct mfi_mpi2_request_raid_scsi_io	*io_request;
795227068Sambrisko	struct IO_REQUEST_INFO io_info;
796227068Sambrisko
797227068Sambrisko	device_id = mfi_cmd->cm_frame->io.header.target_id;
798227068Sambrisko	io_request = cmd->io_request;
799227068Sambrisko	io_request->RaidContext.TargetID = device_id;
800227068Sambrisko	io_request->RaidContext.Status = 0;
801227068Sambrisko	io_request->RaidContext.exStatus =0;
802227068Sambrisko
803227068Sambrisko	start_lba_lo = mfi_cmd->cm_frame->io.lba_lo;
804227068Sambrisko	start_lba_hi = mfi_cmd->cm_frame->io.lba_hi;
805227068Sambrisko
806227068Sambrisko	memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO));
807227068Sambrisko	io_info.ldStartBlock = ((uint64_t)start_lba_hi << 32) | start_lba_lo;
808227068Sambrisko	io_info.numBlocks = mfi_cmd->cm_frame->io.header.data_len;
809227068Sambrisko	io_info.ldTgtId = device_id;
810227068Sambrisko	if ((mfi_cmd->cm_frame->header.flags & MFI_FRAME_DIR_READ) ==
811227068Sambrisko	    MFI_FRAME_DIR_READ)
812227068Sambrisko		io_info.isRead = 1;
813227068Sambrisko
814227068Sambrisko		io_request->RaidContext.timeoutValue
815227068Sambrisko		     = MFI_FUSION_FP_DEFAULT_TIMEOUT;
816227068Sambrisko		io_request->Function = MPI2_FUNCTION_LD_IO_REQUEST;
817227068Sambrisko		io_request->DevHandle = device_id;
818227068Sambrisko		cmd->request_desc->header.RequestFlags
819227068Sambrisko		    = (MFI_REQ_DESCRIPT_FLAGS_LD_IO
820227068Sambrisko		    << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
821233711Sambrisko	if ((io_request->IoFlags == 6) && (io_info.numBlocks == 0))
822227068Sambrisko		io_request->RaidContext.RegLockLength = 0x100;
823227068Sambrisko	io_request->DataLength = mfi_cmd->cm_frame->io.header.data_len
824227068Sambrisko	    * MFI_SECTOR_LEN;
825227068Sambrisko}
826227068Sambrisko
827235016Sambriskoint
828235016Sambriskomfi_tbolt_is_ldio(struct mfi_command *mfi_cmd)
829227068Sambrisko{
830233711Sambrisko	if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_READ
831227068Sambrisko	    || mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
832227068Sambrisko		return 1;
833227068Sambrisko	else
834227068Sambrisko		return 0;
835227068Sambrisko}
836227068Sambrisko
837227068Sambriskoint
838235016Sambriskomfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
839235016Sambrisko    struct mfi_cmd_tbolt *cmd)
840227068Sambrisko{
841227068Sambrisko	uint32_t device_id;
842227068Sambrisko	uint32_t sge_count;
843227068Sambrisko	uint8_t cdb[32], cdb_len;
844227068Sambrisko
845227068Sambrisko	memset(cdb, 0, 32);
846227068Sambrisko	struct mfi_mpi2_request_raid_scsi_io *io_request = cmd->io_request;
847227068Sambrisko
848227068Sambrisko	device_id = mfi_cmd->cm_frame->header.target_id;
849227068Sambrisko
850227068Sambrisko	/* Have to build CDB here for TB as BSD don't have a scsi layer */
851233711Sambrisko	if ((cdb_len = mfi_tbolt_build_cdb(sc, mfi_cmd, cdb)) == 1)
852227068Sambrisko		return 1;
853227068Sambrisko
854227068Sambrisko	/* Just the CDB length,rest of the Flags are zero */
855227068Sambrisko	io_request->IoFlags = cdb_len;
856227068Sambrisko	memcpy(io_request->CDB.CDB32, cdb, 32);
857227068Sambrisko
858227068Sambrisko	if (mfi_tbolt_is_ldio(mfi_cmd))
859227068Sambrisko		mfi_tbolt_build_ldio(sc, mfi_cmd , cmd);
860227068Sambrisko	else
861227068Sambrisko		return 1;
862227068Sambrisko
863227068Sambrisko	/*
864227068Sambrisko	 * Construct SGL
865227068Sambrisko	 */
866227068Sambrisko	sge_count = mfi_tbolt_make_sgl(sc, mfi_cmd,
867227068Sambrisko	    (pMpi25IeeeSgeChain64_t) &io_request->SGL, cmd);
868227068Sambrisko	if (sge_count > sc->mfi_max_sge) {
869227068Sambrisko		device_printf(sc->mfi_dev, "Error. sge_count (0x%x) exceeds "
870227068Sambrisko		    "max (0x%x) allowed\n", sge_count, sc->mfi_max_sge);
871227068Sambrisko		return 1;
872227068Sambrisko	}
873227068Sambrisko	io_request->RaidContext.numSGE = sge_count;
874227068Sambrisko	io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
875227068Sambrisko
876227068Sambrisko	if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
877227068Sambrisko		io_request->Control = MPI2_SCSIIO_CONTROL_WRITE;
878227068Sambrisko	else
879227068Sambrisko		io_request->Control = MPI2_SCSIIO_CONTROL_READ;
880227068Sambrisko
881227068Sambrisko	io_request->SGLOffset0 = offsetof(
882227068Sambrisko	    struct mfi_mpi2_request_raid_scsi_io, SGL)/4;
883227068Sambrisko
884227068Sambrisko	io_request->SenseBufferLowAddress = mfi_cmd->cm_sense_busaddr;
885227068Sambrisko	io_request->SenseBufferLength = MFI_SENSE_LEN;
886227068Sambrisko	return 0;
887227068Sambrisko}
888227068Sambrisko
889227068Sambriskostatic int
890227068Sambriskomfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
891227068Sambrisko    uint8_t *cdb)
892227068Sambrisko{
893227068Sambrisko	uint32_t lba_lo, lba_hi, num_lba;
894227068Sambrisko	uint8_t cdb_len;
895227068Sambrisko
896233711Sambrisko	if (mfi_cmd == NULL || cdb == NULL)
897227068Sambrisko		return 1;
898227068Sambrisko	num_lba = mfi_cmd->cm_frame->io.header.data_len;
899227068Sambrisko	lba_lo = mfi_cmd->cm_frame->io.lba_lo;
900227068Sambrisko	lba_hi = mfi_cmd->cm_frame->io.lba_hi;
901227068Sambrisko
902235014Sambrisko	if (lba_hi == 0 && (num_lba <= 0xFF) && (lba_lo <= 0x1FFFFF)) {
903227068Sambrisko		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
904227068Sambrisko			/* Read 6 or Write 6 */
905227068Sambrisko			cdb[0] = (uint8_t) (0x0A);
906227068Sambrisko		else
907227068Sambrisko			cdb[0] = (uint8_t) (0x08);
908227068Sambrisko
909227068Sambrisko		cdb[4] = (uint8_t) num_lba;
910227068Sambrisko		cdb[3] = (uint8_t) (lba_lo & 0xFF);
911227068Sambrisko		cdb[2] = (uint8_t) (lba_lo >> 8);
912227068Sambrisko		cdb[1] = (uint8_t) ((lba_lo >> 16) & 0x1F);
913227068Sambrisko		cdb_len = 6;
914227068Sambrisko	}
915235014Sambrisko	else if (lba_hi == 0 && (num_lba <= 0xFFFF) && (lba_lo <= 0xFFFFFFFF)) {
916227068Sambrisko		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
917227068Sambrisko			/* Read 10 or Write 10 */
918227068Sambrisko			cdb[0] = (uint8_t) (0x2A);
919227068Sambrisko		else
920227068Sambrisko			cdb[0] = (uint8_t) (0x28);
921227068Sambrisko		cdb[8] = (uint8_t) (num_lba & 0xFF);
922227068Sambrisko		cdb[7] = (uint8_t) (num_lba >> 8);
923227068Sambrisko		cdb[5] = (uint8_t) (lba_lo & 0xFF);
924227068Sambrisko		cdb[4] = (uint8_t) (lba_lo >> 8);
925227068Sambrisko		cdb[3] = (uint8_t) (lba_lo >> 16);
926227068Sambrisko		cdb[2] = (uint8_t) (lba_lo >> 24);
927227068Sambrisko		cdb_len = 10;
928235016Sambrisko	} else if ((num_lba > 0xFFFF) && (lba_hi == 0)) {
929227068Sambrisko		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
930227068Sambrisko			/* Read 12 or Write 12 */
931227068Sambrisko			cdb[0] = (uint8_t) (0xAA);
932227068Sambrisko		else
933227068Sambrisko			cdb[0] = (uint8_t) (0xA8);
934227068Sambrisko		cdb[9] = (uint8_t) (num_lba & 0xFF);
935227068Sambrisko		cdb[8] = (uint8_t) (num_lba >> 8);
936227068Sambrisko		cdb[7] = (uint8_t) (num_lba >> 16);
937227068Sambrisko		cdb[6] = (uint8_t) (num_lba >> 24);
938227068Sambrisko		cdb[5] = (uint8_t) (lba_lo & 0xFF);
939227068Sambrisko		cdb[4] = (uint8_t) (lba_lo >> 8);
940227068Sambrisko		cdb[3] = (uint8_t) (lba_lo >> 16);
941227068Sambrisko		cdb[2] = (uint8_t) (lba_lo >> 24);
942227068Sambrisko		cdb_len = 12;
943233711Sambrisko	} else {
944227068Sambrisko		if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
945227068Sambrisko			cdb[0] = (uint8_t) (0x8A);
946227068Sambrisko		else
947227068Sambrisko			cdb[0] = (uint8_t) (0x88);
948227068Sambrisko		cdb[13] = (uint8_t) (num_lba & 0xFF);
949233711Sambrisko		cdb[12] = (uint8_t) (num_lba >> 8);
950233711Sambrisko		cdb[11] = (uint8_t) (num_lba >> 16);
951233711Sambrisko		cdb[10] = (uint8_t) (num_lba >> 24);
952227068Sambrisko		cdb[9] = (uint8_t) (lba_lo & 0xFF);
953227068Sambrisko		cdb[8] = (uint8_t) (lba_lo >> 8);
954233711Sambrisko		cdb[7] = (uint8_t) (lba_lo >> 16);
955233711Sambrisko		cdb[6] = (uint8_t) (lba_lo >> 24);
956227068Sambrisko		cdb[5] = (uint8_t) (lba_hi & 0xFF);
957233711Sambrisko		cdb[4] = (uint8_t) (lba_hi >> 8);
958233711Sambrisko		cdb[3] = (uint8_t) (lba_hi >> 16);
959233711Sambrisko		cdb[2] = (uint8_t) (lba_hi >> 24);
960227068Sambrisko		cdb_len = 16;
961227068Sambrisko	}
962227068Sambrisko	return cdb_len;
963227068Sambrisko}
964227068Sambrisko
965227068Sambriskostatic int
966227068Sambriskomfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
967233711Sambrisko		   pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd)
968227068Sambrisko{
969233711Sambrisko	uint8_t i, sg_processed, sg_to_process;
970227068Sambrisko	uint8_t sge_count, sge_idx;
971227068Sambrisko	union mfi_sgl *os_sgl;
972227068Sambrisko
973227068Sambrisko	/*
974227068Sambrisko	 * Return 0 if there is no data transfer
975227068Sambrisko	 */
976227068Sambrisko	if (!mfi_cmd->cm_sg || !mfi_cmd->cm_len) {
977227068Sambrisko	 	device_printf(sc->mfi_dev, "Buffer empty \n");
978227068Sambrisko		return 0;
979227068Sambrisko	}
980227068Sambrisko	os_sgl = mfi_cmd->cm_sg;
981227068Sambrisko	sge_count = mfi_cmd->cm_frame->header.sg_count;
982227068Sambrisko
983227068Sambrisko	if (sge_count > sc->mfi_max_sge) {
984227068Sambrisko		device_printf(sc->mfi_dev, "sgl ptr %p sg_cnt %d \n",
985233711Sambrisko		    os_sgl, sge_count);
986227068Sambrisko		return sge_count;
987227068Sambrisko	}
988227068Sambrisko
989227068Sambrisko	if (sge_count > sc->max_SGEs_in_main_message)
990227068Sambrisko		/* One element to store the chain info */
991227068Sambrisko		sge_idx = sc->max_SGEs_in_main_message - 1;
992227068Sambrisko	else
993227068Sambrisko		sge_idx = sge_count;
994227068Sambrisko
995227068Sambrisko	for (i = 0; i < sge_idx; i++) {
996227068Sambrisko		/*
997233711Sambrisko		 * For 32bit BSD we are getting 32 bit SGL's from OS
998233711Sambrisko		 * but FW only take 64 bit SGL's so copying from 32 bit
999233711Sambrisko		 * SGL's to 64.
1000233711Sambrisko		 */
1001227068Sambrisko		if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
1002227068Sambrisko			sgl_ptr->Length = os_sgl->sg_skinny[i].len;
1003227068Sambrisko			sgl_ptr->Address = os_sgl->sg_skinny[i].addr;
1004227068Sambrisko		} else {
1005227068Sambrisko			sgl_ptr->Length = os_sgl->sg32[i].len;
1006233711Sambrisko			sgl_ptr->Address = os_sgl->sg32[i].addr;
1007227068Sambrisko		}
1008227068Sambrisko		sgl_ptr->Flags = 0;
1009227068Sambrisko		sgl_ptr++;
1010227068Sambrisko		cmd->io_request->ChainOffset = 0;
1011227068Sambrisko	}
1012227068Sambrisko
1013227068Sambrisko	sg_processed = i;
1014227068Sambrisko
1015227068Sambrisko	if (sg_processed < sge_count) {
1016227068Sambrisko		pMpi25IeeeSgeChain64_t sg_chain;
1017227068Sambrisko		sg_to_process = sge_count - sg_processed;
1018227068Sambrisko		cmd->io_request->ChainOffset =
1019227068Sambrisko		    sc->chain_offset_value_for_main_message;
1020227068Sambrisko		sg_chain = sgl_ptr;
1021227068Sambrisko		/* Prepare chain element */
1022227068Sambrisko		sg_chain->NextChainOffset = 0;
1023227068Sambrisko		sg_chain->Flags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
1024227068Sambrisko		    MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
1025227068Sambrisko		sg_chain->Length =  (sizeof(MPI2_SGE_IO_UNION) *
1026227068Sambrisko		    (sge_count - sg_processed));
1027233711Sambrisko		sg_chain->Address = cmd->sg_frame_phys_addr;
1028227068Sambrisko		sgl_ptr = (pMpi25IeeeSgeChain64_t)cmd->sg_frame;
1029227068Sambrisko		for (; i < sge_count; i++) {
1030227068Sambrisko			if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
1031227068Sambrisko				sgl_ptr->Length = os_sgl->sg_skinny[i].len;
1032227068Sambrisko				sgl_ptr->Address = os_sgl->sg_skinny[i].addr;
1033233711Sambrisko			} else {
1034227068Sambrisko				sgl_ptr->Length = os_sgl->sg32[i].len;
1035233711Sambrisko				sgl_ptr->Address = os_sgl->sg32[i].addr;
1036227068Sambrisko			}
1037227068Sambrisko			sgl_ptr->Flags = 0;
1038227068Sambrisko			sgl_ptr++;
1039227068Sambrisko		}
1040227068Sambrisko	}
1041227068Sambrisko	return sge_count;
1042227068Sambrisko}
1043227068Sambrisko
1044227068Sambriskounion mfi_mpi2_request_descriptor *
1045227068Sambriskomfi_build_and_issue_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd)
1046227068Sambrisko{
1047227068Sambrisko	struct mfi_cmd_tbolt *cmd;
1048227068Sambrisko	union mfi_mpi2_request_descriptor *req_desc = NULL;
1049227068Sambrisko	uint16_t index;
1050227068Sambrisko	cmd = mfi_tbolt_get_cmd(sc);
1051227068Sambrisko	if (!cmd)
1052227068Sambrisko		return NULL;
1053227068Sambrisko	mfi_cmd->cm_extra_frames = cmd->index;
1054227068Sambrisko	cmd->sync_cmd_idx = mfi_cmd->cm_index;
1055227068Sambrisko
1056227068Sambrisko	index = cmd->index;
1057227068Sambrisko	req_desc = mfi_tbolt_get_request_descriptor(sc, index-1);
1058233711Sambrisko	if (mfi_tbolt_build_io(sc, mfi_cmd, cmd))
1059227068Sambrisko		return NULL;
1060227068Sambrisko	req_desc->header.SMID = index;
1061227068Sambrisko	return req_desc;
1062227068Sambrisko}
1063227068Sambrisko
1064227068Sambriskounion mfi_mpi2_request_descriptor *
1065227068Sambriskomfi_tbolt_build_mpt_cmd(struct mfi_softc *sc, struct mfi_command *cmd)
1066227068Sambrisko{
1067227068Sambrisko	union mfi_mpi2_request_descriptor *req_desc = NULL;
1068227068Sambrisko	uint16_t index;
1069227068Sambrisko	if (mfi_build_mpt_pass_thru(sc, cmd)) {
1070227068Sambrisko		device_printf(sc->mfi_dev, "Couldn't build MFI pass thru "
1071227068Sambrisko		    "cmd\n");
1072227068Sambrisko		return NULL;
1073227068Sambrisko	}
1074227068Sambrisko	/* For fusion the frame_count variable is used for SMID */
1075227068Sambrisko	index = cmd->cm_extra_frames;
1076227068Sambrisko
1077227068Sambrisko	req_desc = mfi_tbolt_get_request_descriptor(sc, index - 1);
1078233711Sambrisko	if (!req_desc)
1079227068Sambrisko		return NULL;
1080227068Sambrisko
1081237546Skevlo	bzero(req_desc, sizeof(*req_desc));
1082227068Sambrisko	req_desc->header.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
1083227068Sambrisko	    MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
1084227068Sambrisko	req_desc->header.SMID = index;
1085227068Sambrisko	return req_desc;
1086227068Sambrisko}
1087227068Sambrisko
1088227068Sambriskoint
1089227068Sambriskomfi_tbolt_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
1090227068Sambrisko{
1091227068Sambrisko	struct mfi_frame_header *hdr;
1092227068Sambrisko	uint8_t *cdb;
1093227068Sambrisko	union mfi_mpi2_request_descriptor *req_desc = NULL;
1094227068Sambrisko	int tm = MFI_POLL_TIMEOUT_SECS * 1000;
1095227068Sambrisko
1096227068Sambrisko	hdr = &cm->cm_frame->header;
1097227068Sambrisko	cdb = cm->cm_frame->pass.cdb;
1098233711Sambrisko	if (sc->adpreset)
1099227068Sambrisko		return 1;
1100227068Sambrisko	if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
1101227068Sambrisko		cm->cm_timestamp = time_uptime;
1102227068Sambrisko		mfi_enqueue_busy(cm);
1103227068Sambrisko	}
1104235014Sambrisko	else {	/* still get interrupts for it */
1105235014Sambrisko		hdr->cmd_status = MFI_STAT_INVALID_STATUS;
1106227068Sambrisko		hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
1107227068Sambrisko	}
1108227068Sambrisko
1109227068Sambrisko	if (hdr->cmd == MFI_CMD_PD_SCSI_IO) {
1110227068Sambrisko		/* check for inquiry commands coming from CLI */
1111227068Sambrisko		if (cdb[0] != 0x28 || cdb[0] != 0x2A) {
1112227068Sambrisko			if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) ==
1113227068Sambrisko			    NULL) {
1114227068Sambrisko				device_printf(sc->mfi_dev, "Mapping from MFI "
1115227068Sambrisko				    "to MPT Failed \n");
1116227068Sambrisko				return 1;
1117227068Sambrisko			}
1118227068Sambrisko		}
1119227068Sambrisko		else
1120227068Sambrisko			device_printf(sc->mfi_dev, "DJA NA XXX SYSPDIO\n");
1121227068Sambrisko	}
1122227068Sambrisko	else if (hdr->cmd == MFI_CMD_LD_SCSI_IO ||
1123227068Sambrisko	    hdr->cmd == MFI_CMD_LD_READ || hdr->cmd == MFI_CMD_LD_WRITE) {
1124227068Sambrisko		if ((req_desc = mfi_build_and_issue_cmd(sc, cm)) == NULL) {
1125227068Sambrisko			device_printf(sc->mfi_dev, "LDIO Failed \n");
1126227068Sambrisko			return 1;
1127227068Sambrisko		}
1128227068Sambrisko	} else
1129227068Sambrisko		if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == NULL) {
1130227068Sambrisko			device_printf(sc->mfi_dev, "Mapping from MFI to MPT "
1131227068Sambrisko			    "Failed\n");
1132227068Sambrisko			return 1;
1133227068Sambrisko		}
1134227068Sambrisko	MFI_WRITE4(sc, MFI_ILQP, (req_desc->words & 0xFFFFFFFF));
1135227068Sambrisko	MFI_WRITE4(sc, MFI_IHQP, (req_desc->words >>0x20));
1136227068Sambrisko
1137227068Sambrisko	if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
1138227068Sambrisko		return 0;
1139227068Sambrisko
1140227068Sambrisko	/* This is a polled command, so busy-wait for it to complete. */
1141235014Sambrisko	while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1142227068Sambrisko		DELAY(1000);
1143227068Sambrisko		tm -= 1;
1144227068Sambrisko		if (tm <= 0)
1145235014Sambrisko		break;
1146227068Sambrisko	}
1147235016Sambrisko
1148235014Sambrisko	if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1149227068Sambrisko		device_printf(sc->mfi_dev, "Frame %p timed out "
1150235014Sambrisko		    "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
1151227068Sambrisko		return (ETIMEDOUT);
1152227068Sambrisko	}
1153227068Sambrisko	return 0;
1154227068Sambrisko}
1155227068Sambrisko
1156235016Sambriskostatic void
1157235016Sambriskomfi_issue_pending_cmds_again (struct mfi_softc *sc)
1158227068Sambrisko{
1159233711Sambrisko	struct mfi_command *cm, *tmp;
1160227068Sambrisko
1161227068Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1162233711Sambrisko	TAILQ_FOREACH_REVERSE_SAFE(cm, &sc->mfi_busy, BUSYQ, cm_link, tmp) {
1163227068Sambrisko
1164227068Sambrisko		cm->retry_for_fw_reset++;
1165227068Sambrisko
1166227068Sambrisko		/*
1167227068Sambrisko		 * If a command has continuously been tried multiple times
1168227068Sambrisko		 * and causing a FW reset condition, no further recoveries
1169227068Sambrisko		 * should be performed on the controller
1170227068Sambrisko		 */
1171227068Sambrisko		if (cm->retry_for_fw_reset == 3) {
1172233711Sambrisko			device_printf(sc->mfi_dev, "megaraid_sas: command %d "
1173227068Sambrisko			    "was tried multiple times during adapter reset"
1174227068Sambrisko			    "Shutting down the HBA\n", cm->cm_index);
1175227068Sambrisko			mfi_kill_hba(sc);
1176227068Sambrisko			sc->hw_crit_error = 1;
1177227068Sambrisko			return;
1178227068Sambrisko		}
1179227068Sambrisko
1180227068Sambrisko		if ((cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0) {
1181227068Sambrisko			struct mfi_cmd_tbolt *cmd;
1182227068Sambrisko			mfi_remove_busy(cm);
1183227068Sambrisko			cmd = sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames -
1184227068Sambrisko			    1 ];
1185227068Sambrisko			mfi_tbolt_return_cmd(sc, cmd);
1186227068Sambrisko			if ((cm->cm_flags & MFI_ON_MFIQ_MASK) == 0) {
1187227068Sambrisko				if (cm->cm_frame->dcmd.opcode !=
1188227068Sambrisko				    MFI_DCMD_CTRL_EVENT_WAIT) {
1189227068Sambrisko					device_printf(sc->mfi_dev,
1190227068Sambrisko					    "APJ ****requeue command %d \n",
1191227068Sambrisko					    cm->cm_index);
1192227068Sambrisko					mfi_requeue_ready(cm);
1193227068Sambrisko				}
1194227068Sambrisko			}
1195227068Sambrisko			else
1196227068Sambrisko				mfi_release_command(cm);
1197227068Sambrisko		}
1198227068Sambrisko	}
1199227068Sambrisko	mfi_startio(sc);
1200227068Sambrisko}
1201227068Sambrisko
1202235016Sambriskostatic void
1203235016Sambriskomfi_kill_hba (struct mfi_softc *sc)
1204227068Sambrisko{
1205227068Sambrisko	if (sc->mfi_flags & MFI_FLAGS_TBOLT)
1206227068Sambrisko		MFI_WRITE4 (sc, 0x00,MFI_STOP_ADP);
1207227068Sambrisko	else
1208227068Sambrisko		MFI_WRITE4 (sc, MFI_IDB,MFI_STOP_ADP);
1209227068Sambrisko}
1210227068Sambrisko
1211235016Sambriskostatic void
1212235016Sambriskomfi_process_fw_state_chg_isr(void *arg)
1213227068Sambrisko{
1214227068Sambrisko	struct mfi_softc *sc= (struct mfi_softc *)arg;
1215227068Sambrisko	struct mfi_cmd_tbolt *cmd;
1216227068Sambrisko	int error, status;
1217227068Sambrisko
1218227068Sambrisko	if (sc->adpreset == 1) {
1219233711Sambrisko		device_printf(sc->mfi_dev, "First stage of FW reset "
1220227068Sambrisko		     "initiated...\n");
1221227068Sambrisko
1222227068Sambrisko		sc->mfi_adp_reset(sc);
1223227068Sambrisko		sc->mfi_enable_intr(sc);
1224227068Sambrisko
1225233711Sambrisko		device_printf(sc->mfi_dev, "First stage of reset complete, "
1226227068Sambrisko		    "second stage initiated...\n");
1227227068Sambrisko
1228227068Sambrisko		sc->adpreset = 2;
1229227068Sambrisko
1230227068Sambrisko		/* waiting for about 20 second before start the second init */
1231233711Sambrisko		for (int wait = 0; wait < 20000; wait++)
1232227068Sambrisko			DELAY(1000);
1233233711Sambrisko		device_printf(sc->mfi_dev, "Second stage of FW reset "
1234227068Sambrisko		     "initiated...\n");
1235233711Sambrisko		while ((status = MFI_READ4(sc, MFI_RSR)) & 0x04);
1236227068Sambrisko
1237227068Sambrisko		sc->mfi_disable_intr(sc);
1238227068Sambrisko
1239227068Sambrisko		/* We expect the FW state to be READY */
1240227068Sambrisko		if (mfi_transition_firmware(sc)) {
1241233711Sambrisko			device_printf(sc->mfi_dev, "controller is not in "
1242233711Sambrisko			    "ready state\n");
1243227068Sambrisko			mfi_kill_hba(sc);
1244227068Sambrisko			sc->hw_crit_error= 1;
1245227068Sambrisko			return ;
1246227068Sambrisko		}
1247227068Sambrisko		if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0)
1248227068Sambrisko				return;
1249227068Sambrisko
1250227068Sambrisko		mtx_lock(&sc->mfi_io_lock);
1251227068Sambrisko
1252227068Sambrisko		sc->mfi_enable_intr(sc);
1253227068Sambrisko		sc->adpreset = 0;
1254227068Sambrisko		free(sc->mfi_aen_cm->cm_data, M_MFIBUF);
1255227068Sambrisko		mfi_remove_busy(sc->mfi_aen_cm);
1256227068Sambrisko		cmd = sc->mfi_cmd_pool_tbolt[sc->mfi_aen_cm->cm_extra_frames
1257227068Sambrisko		    - 1];
1258227068Sambrisko		mfi_tbolt_return_cmd(sc, cmd);
1259227068Sambrisko		if (sc->mfi_aen_cm) {
1260227068Sambrisko			mfi_release_command(sc->mfi_aen_cm);
1261227068Sambrisko			sc->mfi_aen_cm = NULL;
1262227068Sambrisko		}
1263235014Sambrisko		if (sc->mfi_map_sync_cm) {
1264235014Sambrisko			mfi_release_command(sc->mfi_map_sync_cm);
1265235014Sambrisko			sc->mfi_map_sync_cm = NULL;
1266227068Sambrisko		}
1267227068Sambrisko		mfi_issue_pending_cmds_again(sc);
1268227068Sambrisko
1269227068Sambrisko		/*
1270227068Sambrisko		 * Issue pending command can result in adapter being marked
1271227068Sambrisko		 * dead because of too many re-tries. Check for that
1272227068Sambrisko		 * condition before clearing the reset condition on the FW
1273227068Sambrisko		 */
1274227068Sambrisko		if (!sc->hw_crit_error) {
1275227068Sambrisko			/*
1276227068Sambrisko			 * Initiate AEN (Asynchronous Event Notification)
1277227068Sambrisko			 */
1278227068Sambrisko			mfi_aen_setup(sc, sc->last_seq_num);
1279227068Sambrisko			sc->issuepend_done = 1;
1280233711Sambrisko			device_printf(sc->mfi_dev, "second stage of reset "
1281227068Sambrisko			    "complete, FW is ready now.\n");
1282227068Sambrisko		} else {
1283233711Sambrisko			device_printf(sc->mfi_dev, "second stage of reset "
1284227068Sambrisko			     "never completed, hba was marked offline.\n");
1285227068Sambrisko		}
1286227068Sambrisko	} else {
1287227068Sambrisko		device_printf(sc->mfi_dev, "mfi_process_fw_state_chg_isr "
1288227068Sambrisko		    "called with unhandled value:%d\n", sc->adpreset);
1289227068Sambrisko	}
1290227068Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1291227068Sambrisko}
1292235014Sambrisko
1293235014Sambrisko/*
1294235014Sambrisko * The ThunderBolt HW has an option for the driver to directly
1295235016Sambrisko * access the underlying disks and operate on the RAID.  To
1296235014Sambrisko * do this there needs to be a capability to keep the RAID controller
1297235014Sambrisko * and driver in sync.  The FreeBSD driver does not take advantage
1298235014Sambrisko * of this feature since it adds a lot of complexity and slows down
1299235014Sambrisko * performance.  Performance is gained by using the controller's
1300235014Sambrisko * cache etc.
1301235014Sambrisko *
1302235014Sambrisko * Even though this driver doesn't access the disks directly, an
1303235014Sambrisko * AEN like command is used to inform the RAID firmware to "sync"
1304235014Sambrisko * with all LD's via the MFI_DCMD_LD_MAP_GET_INFO command.  This
1305235014Sambrisko * command in write mode will return when the RAID firmware has
1306235014Sambrisko * detected a change to the RAID state.  Examples of this type
1307235014Sambrisko * of change are removing a disk.  Once the command returns then
1308235014Sambrisko * the driver needs to acknowledge this and "sync" all LD's again.
1309235014Sambrisko * This repeats until we shutdown.  Then we need to cancel this
1310235014Sambrisko * pending command.
1311235014Sambrisko *
1312235014Sambrisko * If this is not done right the RAID firmware will not remove a
1313235014Sambrisko * pulled drive and the RAID won't go degraded etc.  Effectively,
1314235014Sambrisko * stopping any RAID mangement to functions.
1315235014Sambrisko *
1316235014Sambrisko * Doing another LD sync, requires the use of an event since the
1317235014Sambrisko * driver needs to do a mfi_wait_command and can't do that in an
1318235014Sambrisko * interrupt thread.
1319235014Sambrisko *
1320235014Sambrisko * The driver could get the RAID state via the MFI_DCMD_LD_MAP_GET_INFO
1321235014Sambrisko * That requires a bunch of structure and it is simplier to just do
1322235014Sambrisko * the MFI_DCMD_LD_GET_LIST versus walking the RAID map.
1323235014Sambrisko */
1324235014Sambrisko
1325235014Sambriskovoid
1326235014Sambriskomfi_tbolt_sync_map_info(struct mfi_softc *sc)
1327235014Sambrisko{
1328235014Sambrisko	int error = 0, i;
1329235014Sambrisko	struct mfi_command *cmd;
1330235014Sambrisko	struct mfi_dcmd_frame *dcmd;
1331235014Sambrisko	uint32_t context = 0;
1332235014Sambrisko	union mfi_ld_ref *ld_sync;
1333235014Sambrisko	size_t ld_size;
1334235014Sambrisko	struct mfi_frame_header *hdr;
1335235014Sambrisko	struct mfi_command *cm = NULL;
1336235014Sambrisko	struct mfi_ld_list *list = NULL;
1337235014Sambrisko
1338235014Sambrisko	if (sc->mfi_map_sync_cm != NULL || sc->cm_map_abort)
1339235014Sambrisko		return;
1340235014Sambrisko
1341235014Sambrisko	mtx_lock(&sc->mfi_io_lock);
1342235014Sambrisko	error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
1343235014Sambrisko	    (void **)&list, sizeof(*list));
1344235014Sambrisko	if (error)
1345235014Sambrisko		goto out;
1346235014Sambrisko
1347235014Sambrisko	cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAIN;
1348235014Sambrisko	if (mfi_wait_command(sc, cm) != 0) {
1349235014Sambrisko		device_printf(sc->mfi_dev, "Failed to get device listing\n");
1350235014Sambrisko		goto out;
1351235014Sambrisko	}
1352235014Sambrisko
1353235014Sambrisko	hdr = &cm->cm_frame->header;
1354235014Sambrisko	if (hdr->cmd_status != MFI_STAT_OK) {
1355235014Sambrisko		device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
1356235014Sambrisko			      hdr->cmd_status);
1357235014Sambrisko		goto out;
1358235014Sambrisko	}
1359235014Sambrisko
1360235014Sambrisko	ld_size = sizeof(*ld_sync) * list->ld_count;
1361235014Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1362235014Sambrisko	ld_sync = (union mfi_ld_ref *) malloc(ld_size, M_MFIBUF,
1363235014Sambrisko	     M_WAITOK | M_ZERO);
1364235040Sambrisko	if (ld_sync == NULL) {
1365235040Sambrisko		device_printf(sc->mfi_dev, "Failed to allocate sync\n");
1366235040Sambrisko		goto out;
1367235040Sambrisko	}
1368235014Sambrisko	for (i = 0; i < list->ld_count; i++) {
1369235014Sambrisko		ld_sync[i].ref = list->ld_list[i].ld.ref;
1370235014Sambrisko	}
1371235014Sambrisko
1372235014Sambrisko	mtx_lock(&sc->mfi_io_lock);
1373235040Sambrisko	if ((cmd = mfi_dequeue_free(sc)) == NULL) {
1374235040Sambrisko		device_printf(sc->mfi_dev, "Failed to get command\n");
1375235040Sambrisko		free(ld_sync, M_MFIBUF);
1376235040Sambrisko		goto out;
1377235040Sambrisko	}
1378235040Sambrisko
1379235014Sambrisko	context = cmd->cm_frame->header.context;
1380235014Sambrisko	bzero(cmd->cm_frame, sizeof(union mfi_frame));
1381235014Sambrisko	cmd->cm_frame->header.context = context;
1382235014Sambrisko
1383235014Sambrisko	dcmd = &cmd->cm_frame->dcmd;
1384235014Sambrisko	bzero(dcmd->mbox, MFI_MBOX_SIZE);
1385235014Sambrisko	dcmd->header.cmd = MFI_CMD_DCMD;
1386235014Sambrisko	dcmd->header.flags = MFI_FRAME_DIR_WRITE;
1387235014Sambrisko	dcmd->header.timeout = 0;
1388235014Sambrisko	dcmd->header.data_len = ld_size;
1389235014Sambrisko	dcmd->header.scsi_status = 0;
1390235014Sambrisko	dcmd->opcode = MFI_DCMD_LD_MAP_GET_INFO;
1391235014Sambrisko	cmd->cm_sg = &dcmd->sgl;
1392235014Sambrisko	cmd->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1393235014Sambrisko	cmd->cm_data = ld_sync;
1394235014Sambrisko	cmd->cm_private = ld_sync;
1395235014Sambrisko
1396235014Sambrisko	cmd->cm_len = ld_size;
1397235014Sambrisko	cmd->cm_complete = mfi_sync_map_complete;
1398235014Sambrisko	sc->mfi_map_sync_cm = cmd;
1399235014Sambrisko
1400235014Sambrisko	cmd->cm_flags = MFI_CMD_DATAOUT;
1401235014Sambrisko	cmd->cm_frame->dcmd.mbox[0] = list->ld_count;
1402235014Sambrisko	cmd->cm_frame->dcmd.mbox[1] = MFI_DCMD_MBOX_PEND_FLAG;
1403235014Sambrisko
1404235014Sambrisko	if ((error = mfi_mapcmd(sc, cmd)) != 0) {
1405235014Sambrisko		device_printf(sc->mfi_dev, "failed to send map sync\n");
1406235040Sambrisko		free(ld_sync, M_MFIBUF);
1407235040Sambrisko		sc->mfi_map_sync_cm = NULL;
1408235040Sambrisko		mfi_requeue_ready(cmd);
1409235040Sambrisko		goto out;
1410235014Sambrisko	}
1411235014Sambrisko
1412235014Sambriskoout:
1413235014Sambrisko	if (list)
1414235014Sambrisko		free(list, M_MFIBUF);
1415235014Sambrisko	if (cm)
1416235014Sambrisko		mfi_release_command(cm);
1417235014Sambrisko	mtx_unlock(&sc->mfi_io_lock);
1418235014Sambrisko}
1419235014Sambrisko
1420235014Sambriskostatic void
1421235014Sambriskomfi_sync_map_complete(struct mfi_command *cm)
1422235014Sambrisko{
1423235014Sambrisko	struct mfi_frame_header *hdr;
1424235014Sambrisko	struct mfi_softc *sc;
1425235014Sambrisko	int aborted = 0;
1426235014Sambrisko
1427235014Sambrisko	sc = cm->cm_sc;
1428235014Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1429235014Sambrisko
1430235014Sambrisko	hdr = &cm->cm_frame->header;
1431235014Sambrisko
1432235014Sambrisko	if (sc->mfi_map_sync_cm == NULL)
1433235014Sambrisko		return;
1434235014Sambrisko
1435235014Sambrisko	if (sc->cm_map_abort ||
1436235014Sambrisko	    hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1437235014Sambrisko		sc->cm_map_abort = 0;
1438235014Sambrisko		aborted = 1;
1439235014Sambrisko	}
1440235014Sambrisko
1441235014Sambrisko	free(cm->cm_data, M_MFIBUF);
1442235014Sambrisko	sc->mfi_map_sync_cm = NULL;
1443235014Sambrisko	wakeup(&sc->mfi_map_sync_cm);
1444235014Sambrisko	mfi_release_command(cm);
1445235014Sambrisko
1446235014Sambrisko	/* set it up again so the driver can catch more events */
1447235014Sambrisko	if (!aborted) {
1448235014Sambrisko		mfi_queue_map_sync(sc);
1449235014Sambrisko	}
1450235014Sambrisko}
1451235014Sambrisko
1452235014Sambriskostatic void
1453235014Sambriskomfi_queue_map_sync(struct mfi_softc *sc)
1454235014Sambrisko{
1455235014Sambrisko	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1456235014Sambrisko	taskqueue_enqueue(taskqueue_swi, &sc->mfi_map_sync_task);
1457235014Sambrisko}
1458235014Sambrisko
1459235014Sambriskovoid
1460235014Sambriskomfi_handle_map_sync(void *context, int pending)
1461235014Sambrisko{
1462235014Sambrisko	struct mfi_softc *sc;
1463235014Sambrisko
1464235014Sambrisko	sc = context;
1465235014Sambrisko	mfi_tbolt_sync_map_info(sc);
1466235014Sambrisko}
1467