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