12e21a3efSScott Long /*-
2eebd9d53SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
42e21a3efSScott Long * Copyright (c) 2006 IronPort Systems
52e21a3efSScott Long * All rights reserved.
62e21a3efSScott Long *
72e21a3efSScott Long * Redistribution and use in source and binary forms, with or without
82e21a3efSScott Long * modification, are permitted provided that the following conditions
92e21a3efSScott Long * are met:
102e21a3efSScott Long * 1. Redistributions of source code must retain the above copyright
112e21a3efSScott Long * notice, this list of conditions and the following disclaimer.
122e21a3efSScott Long * 2. Redistributions in binary form must reproduce the above copyright
132e21a3efSScott Long * notice, this list of conditions and the following disclaimer in the
142e21a3efSScott Long * documentation and/or other materials provided with the distribution.
152e21a3efSScott Long *
162e21a3efSScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172e21a3efSScott Long * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182e21a3efSScott Long * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192e21a3efSScott Long * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202e21a3efSScott Long * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212e21a3efSScott Long * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222e21a3efSScott Long * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232e21a3efSScott Long * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242e21a3efSScott Long * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252e21a3efSScott Long * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262e21a3efSScott Long * SUCH DAMAGE.
272e21a3efSScott Long */
28610f2ef3SScott Long /*-
29610f2ef3SScott Long * Copyright (c) 2007 LSI Corp.
30610f2ef3SScott Long * Copyright (c) 2007 Rajesh Prabhakaran.
31610f2ef3SScott Long * All rights reserved.
32610f2ef3SScott Long *
33610f2ef3SScott Long * Redistribution and use in source and binary forms, with or without
34610f2ef3SScott Long * modification, are permitted provided that the following conditions
35610f2ef3SScott Long * are met:
36610f2ef3SScott Long * 1. Redistributions of source code must retain the above copyright
37610f2ef3SScott Long * notice, this list of conditions and the following disclaimer.
38610f2ef3SScott Long * 2. Redistributions in binary form must reproduce the above copyright
39610f2ef3SScott Long * notice, this list of conditions and the following disclaimer in the
40610f2ef3SScott Long * documentation and/or other materials provided with the distribution.
41610f2ef3SScott Long *
42610f2ef3SScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
43610f2ef3SScott Long * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44610f2ef3SScott Long * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45610f2ef3SScott Long * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
46610f2ef3SScott Long * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47610f2ef3SScott Long * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48610f2ef3SScott Long * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49610f2ef3SScott Long * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50610f2ef3SScott Long * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51610f2ef3SScott Long * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52610f2ef3SScott Long * SUCH DAMAGE.
53610f2ef3SScott Long */
542e21a3efSScott Long
552e21a3efSScott Long #include <sys/cdefs.h>
562e21a3efSScott Long #include "opt_mfi.h"
572e21a3efSScott Long
582e21a3efSScott Long #include <sys/param.h>
592e21a3efSScott Long #include <sys/systm.h>
6047b470b9SDoug Ambrisko #include <sys/sysctl.h>
612e21a3efSScott Long #include <sys/malloc.h>
622e21a3efSScott Long #include <sys/kernel.h>
63741367d5SDoug Ambrisko #include <sys/poll.h>
64741367d5SDoug Ambrisko #include <sys/selinfo.h>
652e21a3efSScott Long #include <sys/bus.h>
662e21a3efSScott Long #include <sys/conf.h>
672e21a3efSScott Long #include <sys/eventhandler.h>
682e21a3efSScott Long #include <sys/rman.h>
692e21a3efSScott Long #include <sys/bio.h>
702e21a3efSScott Long #include <sys/ioccom.h>
71741367d5SDoug Ambrisko #include <sys/uio.h>
72741367d5SDoug Ambrisko #include <sys/proc.h>
73441f6d5dSScott Long #include <sys/signalvar.h>
74da146236SJohn Baldwin #include <sys/sysent.h>
75a6ba0fd6SDoug Ambrisko #include <sys/taskqueue.h>
762e21a3efSScott Long
772e21a3efSScott Long #include <machine/bus.h>
782e21a3efSScott Long #include <machine/resource.h>
792e21a3efSScott Long
802e21a3efSScott Long #include <dev/mfi/mfireg.h>
812e21a3efSScott Long #include <dev/mfi/mfi_ioctl.h>
822e21a3efSScott Long #include <dev/mfi/mfivar.h>
830d9a4ef3SDoug Ambrisko #include <sys/interrupt.h>
840d9a4ef3SDoug Ambrisko #include <sys/priority.h>
852e21a3efSScott Long
862e21a3efSScott Long static int mfi_alloc_commands(struct mfi_softc *);
872e21a3efSScott Long static int mfi_comms_init(struct mfi_softc *);
882e21a3efSScott Long static int mfi_get_controller_info(struct mfi_softc *);
89741367d5SDoug Ambrisko static int mfi_get_log_state(struct mfi_softc *,
90fb595e7aSPaul Saab struct mfi_evt_log_state **);
91c1ed06a8SJohn Baldwin static int mfi_parse_entries(struct mfi_softc *, int, int);
922e21a3efSScott Long static void mfi_data_cb(void *, bus_dma_segment_t *, int, int);
932e21a3efSScott Long static void mfi_startup(void *arg);
942e21a3efSScott Long static void mfi_intr(void *arg);
95c0b332d1SPaul Saab static void mfi_ldprobe(struct mfi_softc *sc);
960d9a4ef3SDoug Ambrisko static void mfi_syspdprobe(struct mfi_softc *sc);
97a6ba0fd6SDoug Ambrisko static void mfi_handle_evt(void *context, int pending);
98741367d5SDoug Ambrisko static int mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
99741367d5SDoug Ambrisko static void mfi_aen_complete(struct mfi_command *);
100c0b332d1SPaul Saab static int mfi_add_ld(struct mfi_softc *sc, int);
101c0b332d1SPaul Saab static void mfi_add_ld_complete(struct mfi_command *);
1020d9a4ef3SDoug Ambrisko static int mfi_add_sys_pd(struct mfi_softc *sc, int);
1030d9a4ef3SDoug Ambrisko static void mfi_add_sys_pd_complete(struct mfi_command *);
1042e21a3efSScott Long static struct mfi_command * mfi_bio_command(struct mfi_softc *);
1052e21a3efSScott Long static void mfi_bio_complete(struct mfi_command *);
1060d9a4ef3SDoug Ambrisko static struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*);
1070d9a4ef3SDoug Ambrisko static struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*);
1082e21a3efSScott Long static int mfi_send_frame(struct mfi_softc *, struct mfi_command *);
10908c89430SSteven Hartland static int mfi_std_send_frame(struct mfi_softc *, struct mfi_command *);
11058ef3154SDoug Ambrisko static int mfi_abort(struct mfi_softc *, struct mfi_command **);
11100b4e54aSWarner Losh static int mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, struct thread *);
1125ba21ff1SScott Long static void mfi_timeout(void *);
1130929b669SScott Long static int mfi_user_command(struct mfi_softc *,
1140929b669SScott Long struct mfi_ioc_passthru *);
115610f2ef3SScott Long static void mfi_enable_intr_xscale(struct mfi_softc *sc);
116610f2ef3SScott Long static void mfi_enable_intr_ppc(struct mfi_softc *sc);
117610f2ef3SScott Long static int32_t mfi_read_fw_status_xscale(struct mfi_softc *sc);
118610f2ef3SScott Long static int32_t mfi_read_fw_status_ppc(struct mfi_softc *sc);
119610f2ef3SScott Long static int mfi_check_clear_intr_xscale(struct mfi_softc *sc);
120610f2ef3SScott Long static int mfi_check_clear_intr_ppc(struct mfi_softc *sc);
121a6ba0fd6SDoug Ambrisko static void mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add,
122a6ba0fd6SDoug Ambrisko uint32_t frame_cnt);
123a6ba0fd6SDoug Ambrisko static void mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add,
124a6ba0fd6SDoug Ambrisko uint32_t frame_cnt);
1250d9a4ef3SDoug Ambrisko static int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode);
1260d9a4ef3SDoug Ambrisko static void mfi_config_unlock(struct mfi_softc *sc, int locked);
1270d9a4ef3SDoug Ambrisko static int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm);
1280d9a4ef3SDoug Ambrisko static void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm);
1290d9a4ef3SDoug Ambrisko static int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm);
13047b470b9SDoug Ambrisko
1317029da5cSPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
1327029da5cSPawel Biernacki "MFI driver parameters");
13347b470b9SDoug Ambrisko static int mfi_event_locale = MFI_EVT_LOCALE_ALL;
13408c89430SSteven Hartland SYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RWTUN, &mfi_event_locale,
13547b470b9SDoug Ambrisko 0, "event message locale");
136a1adc445SDoug Ambrisko
137c953d939SScott Long static int mfi_event_class = MFI_EVT_CLASS_INFO;
13808c89430SSteven Hartland SYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RWTUN, &mfi_event_class,
13947b470b9SDoug Ambrisko 0, "event message class");
14047b470b9SDoug Ambrisko
1410929b669SScott Long static int mfi_max_cmds = 128;
14208c89430SSteven Hartland SYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RDTUN, &mfi_max_cmds,
14308c89430SSteven Hartland 0, "Max commands limit (-1 = controller limit)");
1440929b669SScott Long
145a6ba0fd6SDoug Ambrisko static int mfi_detect_jbod_change = 1;
14608c89430SSteven Hartland SYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RWTUN,
147a6ba0fd6SDoug Ambrisko &mfi_detect_jbod_change, 0, "Detect a change to a JBOD");
148a6ba0fd6SDoug Ambrisko
14908c89430SSteven Hartland int mfi_polled_cmd_timeout = MFI_POLL_TIMEOUT_SECS;
15008c89430SSteven Hartland SYSCTL_INT(_hw_mfi, OID_AUTO, polled_cmd_timeout, CTLFLAG_RWTUN,
15108c89430SSteven Hartland &mfi_polled_cmd_timeout, 0,
15208c89430SSteven Hartland "Polled command timeout - used for firmware flash etc (in seconds)");
15308c89430SSteven Hartland
154f108bdaaSSteven Hartland static int mfi_cmd_timeout = MFI_CMD_TIMEOUT;
155f108bdaaSSteven Hartland SYSCTL_INT(_hw_mfi, OID_AUTO, cmd_timeout, CTLFLAG_RWTUN, &mfi_cmd_timeout,
156f108bdaaSSteven Hartland 0, "Command timeout (in seconds)");
157f108bdaaSSteven Hartland
1582e21a3efSScott Long /* Management interface */
1592e21a3efSScott Long static d_open_t mfi_open;
1602e21a3efSScott Long static d_close_t mfi_close;
1612e21a3efSScott Long static d_ioctl_t mfi_ioctl;
162741367d5SDoug Ambrisko static d_poll_t mfi_poll;
1632e21a3efSScott Long
1642e21a3efSScott Long static struct cdevsw mfi_cdevsw = {
1652e21a3efSScott Long .d_version = D_VERSION,
1662e21a3efSScott Long .d_flags = 0,
1672e21a3efSScott Long .d_open = mfi_open,
1682e21a3efSScott Long .d_close = mfi_close,
1692e21a3efSScott Long .d_ioctl = mfi_ioctl,
170741367d5SDoug Ambrisko .d_poll = mfi_poll,
1712e21a3efSScott Long .d_name = "mfi",
1722e21a3efSScott Long };
1732e21a3efSScott Long
1742e21a3efSScott Long MALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
1752e21a3efSScott Long
1762e21a3efSScott Long #define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
1770d9a4ef3SDoug Ambrisko struct mfi_skinny_dma_info mfi_skinny;
1782e21a3efSScott Long
179610f2ef3SScott Long static void
mfi_enable_intr_xscale(struct mfi_softc * sc)180610f2ef3SScott Long mfi_enable_intr_xscale(struct mfi_softc *sc)
181610f2ef3SScott Long {
182610f2ef3SScott Long MFI_WRITE4(sc, MFI_OMSK, 0x01);
183610f2ef3SScott Long }
184610f2ef3SScott Long
185610f2ef3SScott Long static void
mfi_enable_intr_ppc(struct mfi_softc * sc)186610f2ef3SScott Long mfi_enable_intr_ppc(struct mfi_softc *sc)
187610f2ef3SScott Long {
188fa1e6ef4SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_1078) {
1890d9a4ef3SDoug Ambrisko MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
190610f2ef3SScott Long MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
1910d9a4ef3SDoug Ambrisko }
1920d9a4ef3SDoug Ambrisko else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
1930d9a4ef3SDoug Ambrisko MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
194fa1e6ef4SDoug Ambrisko MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM);
195fa1e6ef4SDoug Ambrisko }
1960d9a4ef3SDoug Ambrisko else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
1970d9a4ef3SDoug Ambrisko MFI_WRITE4(sc, MFI_OMSK, ~0x00000001);
1980d9a4ef3SDoug Ambrisko }
199610f2ef3SScott Long }
200610f2ef3SScott Long
201610f2ef3SScott Long static int32_t
mfi_read_fw_status_xscale(struct mfi_softc * sc)202610f2ef3SScott Long mfi_read_fw_status_xscale(struct mfi_softc *sc)
203610f2ef3SScott Long {
204610f2ef3SScott Long return MFI_READ4(sc, MFI_OMSG0);
205610f2ef3SScott Long }
206610f2ef3SScott Long
207610f2ef3SScott Long static int32_t
mfi_read_fw_status_ppc(struct mfi_softc * sc)208610f2ef3SScott Long mfi_read_fw_status_ppc(struct mfi_softc *sc)
209610f2ef3SScott Long {
210610f2ef3SScott Long return MFI_READ4(sc, MFI_OSP0);
211610f2ef3SScott Long }
212610f2ef3SScott Long
213610f2ef3SScott Long static int
mfi_check_clear_intr_xscale(struct mfi_softc * sc)214610f2ef3SScott Long mfi_check_clear_intr_xscale(struct mfi_softc *sc)
215610f2ef3SScott Long {
216610f2ef3SScott Long int32_t status;
217610f2ef3SScott Long
218610f2ef3SScott Long status = MFI_READ4(sc, MFI_OSTS);
219610f2ef3SScott Long if ((status & MFI_OSTS_INTR_VALID) == 0)
220610f2ef3SScott Long return 1;
221610f2ef3SScott Long
222610f2ef3SScott Long MFI_WRITE4(sc, MFI_OSTS, status);
223610f2ef3SScott Long return 0;
224610f2ef3SScott Long }
225610f2ef3SScott Long
226610f2ef3SScott Long static int
mfi_check_clear_intr_ppc(struct mfi_softc * sc)227610f2ef3SScott Long mfi_check_clear_intr_ppc(struct mfi_softc *sc)
228610f2ef3SScott Long {
229610f2ef3SScott Long int32_t status;
230610f2ef3SScott Long
231610f2ef3SScott Long status = MFI_READ4(sc, MFI_OSTS);
232fa1e6ef4SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_1078) {
233fa1e6ef4SDoug Ambrisko if (!(status & MFI_1078_RM)) {
234610f2ef3SScott Long return 1;
235fa1e6ef4SDoug Ambrisko }
2360d9a4ef3SDoug Ambrisko }
2370d9a4ef3SDoug Ambrisko else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
238fa1e6ef4SDoug Ambrisko if (!(status & MFI_GEN2_RM)) {
239fa1e6ef4SDoug Ambrisko return 1;
240fa1e6ef4SDoug Ambrisko }
241fa1e6ef4SDoug Ambrisko }
2420d9a4ef3SDoug Ambrisko else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
2430d9a4ef3SDoug Ambrisko if (!(status & MFI_SKINNY_RM)) {
2440d9a4ef3SDoug Ambrisko return 1;
2450d9a4ef3SDoug Ambrisko }
2460d9a4ef3SDoug Ambrisko }
2470d9a4ef3SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY)
2480d9a4ef3SDoug Ambrisko MFI_WRITE4(sc, MFI_OSTS, status);
2490d9a4ef3SDoug Ambrisko else
250610f2ef3SScott Long MFI_WRITE4(sc, MFI_ODCR0, status);
251610f2ef3SScott Long return 0;
252610f2ef3SScott Long }
253610f2ef3SScott Long
254610f2ef3SScott Long static void
mfi_issue_cmd_xscale(struct mfi_softc * sc,bus_addr_t bus_add,uint32_t frame_cnt)2550d9a4ef3SDoug Ambrisko mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
256610f2ef3SScott Long {
257610f2ef3SScott Long MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt);
258610f2ef3SScott Long }
259610f2ef3SScott Long
260610f2ef3SScott Long static void
mfi_issue_cmd_ppc(struct mfi_softc * sc,bus_addr_t bus_add,uint32_t frame_cnt)2610d9a4ef3SDoug Ambrisko mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
262610f2ef3SScott Long {
2630d9a4ef3SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
2640d9a4ef3SDoug Ambrisko MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt <<1)|1 );
2650d9a4ef3SDoug Ambrisko MFI_WRITE4(sc, MFI_IQPH, 0x00000000);
2660d9a4ef3SDoug Ambrisko } else {
267610f2ef3SScott Long MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt <<1)|1 );
268610f2ef3SScott Long }
2690d9a4ef3SDoug Ambrisko }
270610f2ef3SScott Long
2710d9a4ef3SDoug Ambrisko int
mfi_transition_firmware(struct mfi_softc * sc)2722e21a3efSScott Long mfi_transition_firmware(struct mfi_softc *sc)
2732e21a3efSScott Long {
274cadd4fa0SScott Long uint32_t fw_state, cur_state;
2752e21a3efSScott Long int max_wait, i;
2760d9a4ef3SDoug Ambrisko uint32_t cur_abs_reg_val = 0;
2770d9a4ef3SDoug Ambrisko uint32_t prev_abs_reg_val = 0;
2782e21a3efSScott Long
2790d9a4ef3SDoug Ambrisko cur_abs_reg_val = sc->mfi_read_fw_status(sc);
2800d9a4ef3SDoug Ambrisko fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
2812e21a3efSScott Long while (fw_state != MFI_FWSTATE_READY) {
2822e21a3efSScott Long if (bootverbose)
2832e21a3efSScott Long device_printf(sc->mfi_dev, "Waiting for firmware to "
2842e21a3efSScott Long "become ready\n");
2852e21a3efSScott Long cur_state = fw_state;
2862e21a3efSScott Long switch (fw_state) {
2872e21a3efSScott Long case MFI_FWSTATE_FAULT:
2882e21a3efSScott Long device_printf(sc->mfi_dev, "Firmware fault\n");
2892e21a3efSScott Long return (ENXIO);
2902e21a3efSScott Long case MFI_FWSTATE_WAIT_HANDSHAKE:
2910d9a4ef3SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
2920d9a4ef3SDoug Ambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
2930d9a4ef3SDoug Ambrisko else
2942e21a3efSScott Long MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
2950d9a4ef3SDoug Ambrisko max_wait = MFI_RESET_WAIT_TIME;
2962e21a3efSScott Long break;
2972e21a3efSScott Long case MFI_FWSTATE_OPERATIONAL:
2980d9a4ef3SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
2990d9a4ef3SDoug Ambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, 7);
3000d9a4ef3SDoug Ambrisko else
3012e21a3efSScott Long MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
3020d9a4ef3SDoug Ambrisko max_wait = MFI_RESET_WAIT_TIME;
3032e21a3efSScott Long break;
3042e21a3efSScott Long case MFI_FWSTATE_UNDEFINED:
3052e21a3efSScott Long case MFI_FWSTATE_BB_INIT:
3060d9a4ef3SDoug Ambrisko max_wait = MFI_RESET_WAIT_TIME;
3070d9a4ef3SDoug Ambrisko break;
3080d9a4ef3SDoug Ambrisko case MFI_FWSTATE_FW_INIT_2:
3090d9a4ef3SDoug Ambrisko max_wait = MFI_RESET_WAIT_TIME;
3102e21a3efSScott Long break;
3112e21a3efSScott Long case MFI_FWSTATE_FW_INIT:
3122e21a3efSScott Long case MFI_FWSTATE_FLUSH_CACHE:
3130d9a4ef3SDoug Ambrisko max_wait = MFI_RESET_WAIT_TIME;
3140d9a4ef3SDoug Ambrisko break;
3150d9a4ef3SDoug Ambrisko case MFI_FWSTATE_DEVICE_SCAN:
3160d9a4ef3SDoug Ambrisko max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */
3170d9a4ef3SDoug Ambrisko prev_abs_reg_val = cur_abs_reg_val;
3182e21a3efSScott Long break;
3195dbee633SJohn Baldwin case MFI_FWSTATE_BOOT_MESSAGE_PENDING:
3200d9a4ef3SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
3210d9a4ef3SDoug Ambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG);
3220d9a4ef3SDoug Ambrisko else
3235dbee633SJohn Baldwin MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
3240d9a4ef3SDoug Ambrisko max_wait = MFI_RESET_WAIT_TIME;
3255dbee633SJohn Baldwin break;
3262e21a3efSScott Long default:
3275dbee633SJohn Baldwin device_printf(sc->mfi_dev, "Unknown firmware state %#x\n",
3282e21a3efSScott Long fw_state);
3292e21a3efSScott Long return (ENXIO);
3302e21a3efSScott Long }
3312e21a3efSScott Long for (i = 0; i < (max_wait * 10); i++) {
3320d9a4ef3SDoug Ambrisko cur_abs_reg_val = sc->mfi_read_fw_status(sc);
3330d9a4ef3SDoug Ambrisko fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
3342e21a3efSScott Long if (fw_state == cur_state)
3352e21a3efSScott Long DELAY(100000);
3362e21a3efSScott Long else
3372e21a3efSScott Long break;
3382e21a3efSScott Long }
3390d9a4ef3SDoug Ambrisko if (fw_state == MFI_FWSTATE_DEVICE_SCAN) {
3400d9a4ef3SDoug Ambrisko /* Check the device scanning progress */
3410d9a4ef3SDoug Ambrisko if (prev_abs_reg_val != cur_abs_reg_val) {
3420d9a4ef3SDoug Ambrisko continue;
3430d9a4ef3SDoug Ambrisko }
3440d9a4ef3SDoug Ambrisko }
3452e21a3efSScott Long if (fw_state == cur_state) {
3465dbee633SJohn Baldwin device_printf(sc->mfi_dev, "Firmware stuck in state "
3472e21a3efSScott Long "%#x\n", fw_state);
3482e21a3efSScott Long return (ENXIO);
3492e21a3efSScott Long }
3502e21a3efSScott Long }
3512e21a3efSScott Long return (0);
3522e21a3efSScott Long }
3532e21a3efSScott Long
3542e21a3efSScott Long static void
mfi_addr_cb(void * arg,bus_dma_segment_t * segs,int nsegs,int error)3550d9a4ef3SDoug Ambrisko mfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
3562e21a3efSScott Long {
3570d9a4ef3SDoug Ambrisko bus_addr_t *addr;
3582e21a3efSScott Long
3592e21a3efSScott Long addr = arg;
3602e21a3efSScott Long *addr = segs[0].ds_addr;
3612e21a3efSScott Long }
3622e21a3efSScott Long
3632e21a3efSScott Long int
mfi_attach(struct mfi_softc * sc)3642e21a3efSScott Long mfi_attach(struct mfi_softc *sc)
3652e21a3efSScott Long {
3662e21a3efSScott Long uint32_t status;
3672e21a3efSScott Long int error, commsz, framessz, sensesz;
36808c89430SSteven Hartland int frames, unit, max_fw_sge, max_fw_cmds;
3690d9a4ef3SDoug Ambrisko uint32_t tb_mem_size = 0;
370b5c50320SDoug Ambrisko struct cdev *dev_t;
371216d58bbSDoug Ambrisko
3720d9a4ef3SDoug Ambrisko if (sc == NULL)
3730d9a4ef3SDoug Ambrisko return EINVAL;
374216d58bbSDoug Ambrisko
375a6ba0fd6SDoug Ambrisko device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n",
376a6ba0fd6SDoug Ambrisko MEGASAS_VERSION);
3772e21a3efSScott Long
3782e21a3efSScott Long mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
3798ec5c98bSJohn Baldwin sx_init(&sc->mfi_config_lock, "MFI config");
3802e21a3efSScott Long TAILQ_INIT(&sc->mfi_ld_tqh);
3810d9a4ef3SDoug Ambrisko TAILQ_INIT(&sc->mfi_syspd_tqh);
38258ef3154SDoug Ambrisko TAILQ_INIT(&sc->mfi_ld_pend_tqh);
38358ef3154SDoug Ambrisko TAILQ_INIT(&sc->mfi_syspd_pend_tqh);
384a6ba0fd6SDoug Ambrisko TAILQ_INIT(&sc->mfi_evt_queue);
385a6ba0fd6SDoug Ambrisko TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc);
386ddbffe7fSDoug Ambrisko TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc);
387741367d5SDoug Ambrisko TAILQ_INIT(&sc->mfi_aen_pids);
38835ef86f2SScott Long TAILQ_INIT(&sc->mfi_cam_ccbq);
3892e21a3efSScott Long
3902e21a3efSScott Long mfi_initq_free(sc);
3912e21a3efSScott Long mfi_initq_ready(sc);
3922e21a3efSScott Long mfi_initq_busy(sc);
3932e21a3efSScott Long mfi_initq_bio(sc);
3942e21a3efSScott Long
3950d9a4ef3SDoug Ambrisko sc->adpreset = 0;
3960d9a4ef3SDoug Ambrisko sc->last_seq_num = 0;
3970d9a4ef3SDoug Ambrisko sc->disableOnlineCtrlReset = 1;
3980d9a4ef3SDoug Ambrisko sc->issuepend_done = 1;
3990d9a4ef3SDoug Ambrisko sc->hw_crit_error = 0;
4000d9a4ef3SDoug Ambrisko
401610f2ef3SScott Long if (sc->mfi_flags & MFI_FLAGS_1064R) {
402610f2ef3SScott Long sc->mfi_enable_intr = mfi_enable_intr_xscale;
403610f2ef3SScott Long sc->mfi_read_fw_status = mfi_read_fw_status_xscale;
404610f2ef3SScott Long sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale;
405610f2ef3SScott Long sc->mfi_issue_cmd = mfi_issue_cmd_xscale;
406a6ba0fd6SDoug Ambrisko } else if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
4070d9a4ef3SDoug Ambrisko sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc;
4080d9a4ef3SDoug Ambrisko sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc;
4090d9a4ef3SDoug Ambrisko sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc;
4100d9a4ef3SDoug Ambrisko sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc;
4110d9a4ef3SDoug Ambrisko sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc;
4120d9a4ef3SDoug Ambrisko sc->mfi_adp_reset = mfi_tbolt_adp_reset;
4130d9a4ef3SDoug Ambrisko sc->mfi_tbolt = 1;
4140d9a4ef3SDoug Ambrisko TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh);
415a6ba0fd6SDoug Ambrisko } else {
416610f2ef3SScott Long sc->mfi_enable_intr = mfi_enable_intr_ppc;
417610f2ef3SScott Long sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
418610f2ef3SScott Long sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc;
419610f2ef3SScott Long sc->mfi_issue_cmd = mfi_issue_cmd_ppc;
420610f2ef3SScott Long }
421610f2ef3SScott Long
4222e21a3efSScott Long /* Before we get too far, see if the firmware is working */
4232e21a3efSScott Long if ((error = mfi_transition_firmware(sc)) != 0) {
4242e21a3efSScott Long device_printf(sc->mfi_dev, "Firmware not in READY state, "
4252e21a3efSScott Long "error %d\n", error);
4262e21a3efSScott Long return (ENXIO);
4272e21a3efSScott Long }
4282e21a3efSScott Long
429a6ba0fd6SDoug Ambrisko /* Start: LSIP200113393 */
4300d9a4ef3SDoug Ambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
4310d9a4ef3SDoug Ambrisko 1, 0, /* algnmnt, boundary */
4320d9a4ef3SDoug Ambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
4330d9a4ef3SDoug Ambrisko BUS_SPACE_MAXADDR, /* highaddr */
4340d9a4ef3SDoug Ambrisko NULL, NULL, /* filter, filterarg */
4350d9a4ef3SDoug Ambrisko MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsize */
4360d9a4ef3SDoug Ambrisko 1, /* msegments */
4370d9a4ef3SDoug Ambrisko MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsegsize */
4380d9a4ef3SDoug Ambrisko 0, /* flags */
4390d9a4ef3SDoug Ambrisko NULL, NULL, /* lockfunc, lockarg */
4400d9a4ef3SDoug Ambrisko &sc->verbuf_h_dmat)) {
4410d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n");
4420d9a4ef3SDoug Ambrisko return (ENOMEM);
4430d9a4ef3SDoug Ambrisko }
4440d9a4ef3SDoug Ambrisko if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf,
4450d9a4ef3SDoug Ambrisko BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) {
4460d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n");
4470d9a4ef3SDoug Ambrisko return (ENOMEM);
4480d9a4ef3SDoug Ambrisko }
4490d9a4ef3SDoug Ambrisko bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t));
4500d9a4ef3SDoug Ambrisko bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap,
451a6ba0fd6SDoug Ambrisko sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t),
452a6ba0fd6SDoug Ambrisko mfi_addr_cb, &sc->verbuf_h_busaddr, 0);
453a6ba0fd6SDoug Ambrisko /* End: LSIP200113393 */
4542e21a3efSScott Long
4552e21a3efSScott Long /*
4562e21a3efSScott Long * Get information needed for sizing the contiguous memory for the
4572e21a3efSScott Long * frame pool. Size down the sgl parameter since we know that
458cd853791SKonstantin Belousov * we will never need more than what's required for MFI_MAXPHYS.
4592e21a3efSScott Long * It would be nice if these constants were available at runtime
4602e21a3efSScott Long * instead of compile time.
4612e21a3efSScott Long */
462610f2ef3SScott Long status = sc->mfi_read_fw_status(sc);
46308c89430SSteven Hartland max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK;
46408c89430SSteven Hartland if (mfi_max_cmds > 0 && mfi_max_cmds < max_fw_cmds) {
46508c89430SSteven Hartland device_printf(sc->mfi_dev, "FW MaxCmds = %d, limiting to %d\n",
46608c89430SSteven Hartland max_fw_cmds, mfi_max_cmds);
46708c89430SSteven Hartland sc->mfi_max_fw_cmds = mfi_max_cmds;
46808c89430SSteven Hartland } else {
46908c89430SSteven Hartland sc->mfi_max_fw_cmds = max_fw_cmds;
47008c89430SSteven Hartland }
47178e36c27SScott Long max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
47252c9ce25SScott Long sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1));
4732e21a3efSScott Long
4740d9a4ef3SDoug Ambrisko /* ThunderBolt Support get the contiguous memory */
4750d9a4ef3SDoug Ambrisko
4760d9a4ef3SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
4770d9a4ef3SDoug Ambrisko mfi_tbolt_init_globals(sc);
47808c89430SSteven Hartland device_printf(sc->mfi_dev, "MaxCmd = %d, Drv MaxCmd = %d, "
47908c89430SSteven Hartland "MaxSgl = %d, state = %#x\n", max_fw_cmds,
4800d9a4ef3SDoug Ambrisko sc->mfi_max_fw_cmds, sc->mfi_max_sge, status);
4810d9a4ef3SDoug Ambrisko tb_mem_size = mfi_tbolt_get_memory_requirement(sc);
4820d9a4ef3SDoug Ambrisko
4830d9a4ef3SDoug Ambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
4840d9a4ef3SDoug Ambrisko 1, 0, /* algnmnt, boundary */
4850d9a4ef3SDoug Ambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
4860d9a4ef3SDoug Ambrisko BUS_SPACE_MAXADDR, /* highaddr */
4870d9a4ef3SDoug Ambrisko NULL, NULL, /* filter, filterarg */
4880d9a4ef3SDoug Ambrisko tb_mem_size, /* maxsize */
4890d9a4ef3SDoug Ambrisko 1, /* msegments */
4900d9a4ef3SDoug Ambrisko tb_mem_size, /* maxsegsize */
4910d9a4ef3SDoug Ambrisko 0, /* flags */
4920d9a4ef3SDoug Ambrisko NULL, NULL, /* lockfunc, lockarg */
4930d9a4ef3SDoug Ambrisko &sc->mfi_tb_dmat)) {
4940d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
4950d9a4ef3SDoug Ambrisko return (ENOMEM);
4960d9a4ef3SDoug Ambrisko }
4970d9a4ef3SDoug Ambrisko if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool,
4980d9a4ef3SDoug Ambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) {
4990d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
5000d9a4ef3SDoug Ambrisko return (ENOMEM);
5010d9a4ef3SDoug Ambrisko }
5020d9a4ef3SDoug Ambrisko bzero(sc->request_message_pool, tb_mem_size);
5030d9a4ef3SDoug Ambrisko bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap,
5040d9a4ef3SDoug Ambrisko sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0);
5050d9a4ef3SDoug Ambrisko
5060d9a4ef3SDoug Ambrisko /* For ThunderBolt memory init */
5070d9a4ef3SDoug Ambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
508a6ba0fd6SDoug Ambrisko 0x100, 0, /* alignmnt, boundary */
5090d9a4ef3SDoug Ambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
5100d9a4ef3SDoug Ambrisko BUS_SPACE_MAXADDR, /* highaddr */
5110d9a4ef3SDoug Ambrisko NULL, NULL, /* filter, filterarg */
5120d9a4ef3SDoug Ambrisko MFI_FRAME_SIZE, /* maxsize */
5130d9a4ef3SDoug Ambrisko 1, /* msegments */
5140d9a4ef3SDoug Ambrisko MFI_FRAME_SIZE, /* maxsegsize */
5150d9a4ef3SDoug Ambrisko 0, /* flags */
5160d9a4ef3SDoug Ambrisko NULL, NULL, /* lockfunc, lockarg */
5170d9a4ef3SDoug Ambrisko &sc->mfi_tb_init_dmat)) {
5180d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n");
5190d9a4ef3SDoug Ambrisko return (ENOMEM);
5200d9a4ef3SDoug Ambrisko }
5210d9a4ef3SDoug Ambrisko if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init,
5220d9a4ef3SDoug Ambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) {
5230d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "Cannot allocate init memory\n");
5240d9a4ef3SDoug Ambrisko return (ENOMEM);
5250d9a4ef3SDoug Ambrisko }
5260d9a4ef3SDoug Ambrisko bzero(sc->mfi_tb_init, MFI_FRAME_SIZE);
5270d9a4ef3SDoug Ambrisko bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap,
528a6ba0fd6SDoug Ambrisko sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb,
529a6ba0fd6SDoug Ambrisko &sc->mfi_tb_init_busaddr, 0);
530a6ba0fd6SDoug Ambrisko if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool,
531a6ba0fd6SDoug Ambrisko tb_mem_size)) {
532a6ba0fd6SDoug Ambrisko device_printf(sc->mfi_dev,
533a6ba0fd6SDoug Ambrisko "Thunderbolt pool preparation error\n");
5340d9a4ef3SDoug Ambrisko return 0;
5350d9a4ef3SDoug Ambrisko }
5360d9a4ef3SDoug Ambrisko
5370d9a4ef3SDoug Ambrisko /*
5380d9a4ef3SDoug Ambrisko Allocate DMA memory mapping for MPI2 IOC Init descriptor,
539453130d9SPedro F. Giffuni we are taking it different from what we have allocated for Request
5400d9a4ef3SDoug Ambrisko and reply descriptors to avoid confusion later
5410d9a4ef3SDoug Ambrisko */
5420d9a4ef3SDoug Ambrisko tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST);
5430d9a4ef3SDoug Ambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
5440d9a4ef3SDoug Ambrisko 1, 0, /* algnmnt, boundary */
5450d9a4ef3SDoug Ambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
5460d9a4ef3SDoug Ambrisko BUS_SPACE_MAXADDR, /* highaddr */
5470d9a4ef3SDoug Ambrisko NULL, NULL, /* filter, filterarg */
5480d9a4ef3SDoug Ambrisko tb_mem_size, /* maxsize */
5490d9a4ef3SDoug Ambrisko 1, /* msegments */
5500d9a4ef3SDoug Ambrisko tb_mem_size, /* maxsegsize */
5510d9a4ef3SDoug Ambrisko 0, /* flags */
5520d9a4ef3SDoug Ambrisko NULL, NULL, /* lockfunc, lockarg */
5530d9a4ef3SDoug Ambrisko &sc->mfi_tb_ioc_init_dmat)) {
554a6ba0fd6SDoug Ambrisko device_printf(sc->mfi_dev,
555a6ba0fd6SDoug Ambrisko "Cannot allocate comms DMA tag\n");
5560d9a4ef3SDoug Ambrisko return (ENOMEM);
5570d9a4ef3SDoug Ambrisko }
558a6ba0fd6SDoug Ambrisko if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat,
559a6ba0fd6SDoug Ambrisko (void **)&sc->mfi_tb_ioc_init_desc,
5600d9a4ef3SDoug Ambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) {
5610d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
5620d9a4ef3SDoug Ambrisko return (ENOMEM);
5630d9a4ef3SDoug Ambrisko }
5640d9a4ef3SDoug Ambrisko bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size);
5650d9a4ef3SDoug Ambrisko bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap,
566a6ba0fd6SDoug Ambrisko sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb,
567a6ba0fd6SDoug Ambrisko &sc->mfi_tb_ioc_init_busaddr, 0);
5680d9a4ef3SDoug Ambrisko }
5692e21a3efSScott Long /*
5702e21a3efSScott Long * Create the dma tag for data buffers. Used both for block I/O
5712e21a3efSScott Long * and for various internal data queries.
5722e21a3efSScott Long */
5732e21a3efSScott Long if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
5742e21a3efSScott Long 1, 0, /* algnmnt, boundary */
5752e21a3efSScott Long BUS_SPACE_MAXADDR, /* lowaddr */
5762e21a3efSScott Long BUS_SPACE_MAXADDR, /* highaddr */
5772e21a3efSScott Long NULL, NULL, /* filter, filterarg */
5782e21a3efSScott Long BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
57978e36c27SScott Long sc->mfi_max_sge, /* nsegments */
5802e21a3efSScott Long BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
5812e21a3efSScott Long BUS_DMA_ALLOCNOW, /* flags */
5822e21a3efSScott Long busdma_lock_mutex, /* lockfunc */
5832e21a3efSScott Long &sc->mfi_io_lock, /* lockfuncarg */
5842e21a3efSScott Long &sc->mfi_buffer_dmat)) {
5852e21a3efSScott Long device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n");
5862e21a3efSScott Long return (ENOMEM);
5872e21a3efSScott Long }
5882e21a3efSScott Long
5892e21a3efSScott Long /*
5902e21a3efSScott Long * Allocate DMA memory for the comms queues. Keep it under 4GB for
5912e21a3efSScott Long * efficiency. The mfi_hwcomms struct includes space for 1 reply queue
5922e21a3efSScott Long * entry, so the calculated size here will be will be 1 more than
5932e21a3efSScott Long * mfi_max_fw_cmds. This is apparently a requirement of the hardware.
5942e21a3efSScott Long */
5952e21a3efSScott Long commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) +
5962e21a3efSScott Long sizeof(struct mfi_hwcomms);
5972e21a3efSScott Long if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
5982e21a3efSScott Long 1, 0, /* algnmnt, boundary */
5992e21a3efSScott Long BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
6002e21a3efSScott Long BUS_SPACE_MAXADDR, /* highaddr */
6012e21a3efSScott Long NULL, NULL, /* filter, filterarg */
6022e21a3efSScott Long commsz, /* maxsize */
6032e21a3efSScott Long 1, /* msegments */
6042e21a3efSScott Long commsz, /* maxsegsize */
6052e21a3efSScott Long 0, /* flags */
6062e21a3efSScott Long NULL, NULL, /* lockfunc, lockarg */
6072e21a3efSScott Long &sc->mfi_comms_dmat)) {
6082e21a3efSScott Long device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
6092e21a3efSScott Long return (ENOMEM);
6102e21a3efSScott Long }
6112e21a3efSScott Long if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms,
6122e21a3efSScott Long BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) {
6132e21a3efSScott Long device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
6142e21a3efSScott Long return (ENOMEM);
6152e21a3efSScott Long }
6162e21a3efSScott Long bzero(sc->mfi_comms, commsz);
6172e21a3efSScott Long bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
6180d9a4ef3SDoug Ambrisko sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0);
6192e21a3efSScott Long /*
6202e21a3efSScott Long * Allocate DMA memory for the command frames. Keep them in the
62178e36c27SScott Long * lower 4GB for efficiency. Calculate the size of the commands at
62278e36c27SScott Long * the same time; each command is one 64 byte frame plus a set of
62378e36c27SScott Long * additional frames for holding sg lists or other data.
6242e21a3efSScott Long * The assumption here is that the SG list will start at the second
62578e36c27SScott Long * frame and not use the unused bytes in the first frame. While this
62678e36c27SScott Long * isn't technically correct, it simplifies the calculation and allows
62778e36c27SScott Long * for command frames that might be larger than an mfi_io_frame.
6282e21a3efSScott Long */
6292e21a3efSScott Long if (sizeof(bus_addr_t) == 8) {
63078e36c27SScott Long sc->mfi_sge_size = sizeof(struct mfi_sg64);
6312e21a3efSScott Long sc->mfi_flags |= MFI_FLAGS_SG64;
6322e21a3efSScott Long } else {
63378e36c27SScott Long sc->mfi_sge_size = sizeof(struct mfi_sg32);
6342e21a3efSScott Long }
6350d9a4ef3SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY)
6360d9a4ef3SDoug Ambrisko sc->mfi_sge_size = sizeof(struct mfi_sg_skinny);
63778e36c27SScott Long frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
63878e36c27SScott Long sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
63978e36c27SScott Long framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
6402e21a3efSScott Long if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
6412e21a3efSScott Long 64, 0, /* algnmnt, boundary */
6422e21a3efSScott Long BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
6432e21a3efSScott Long BUS_SPACE_MAXADDR, /* highaddr */
6442e21a3efSScott Long NULL, NULL, /* filter, filterarg */
6452e21a3efSScott Long framessz, /* maxsize */
6462e21a3efSScott Long 1, /* nsegments */
6472e21a3efSScott Long framessz, /* maxsegsize */
6482e21a3efSScott Long 0, /* flags */
6492e21a3efSScott Long NULL, NULL, /* lockfunc, lockarg */
6502e21a3efSScott Long &sc->mfi_frames_dmat)) {
6512e21a3efSScott Long device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n");
6522e21a3efSScott Long return (ENOMEM);
6532e21a3efSScott Long }
6542e21a3efSScott Long if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames,
6552e21a3efSScott Long BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) {
6562e21a3efSScott Long device_printf(sc->mfi_dev, "Cannot allocate frames memory\n");
6572e21a3efSScott Long return (ENOMEM);
6582e21a3efSScott Long }
6592e21a3efSScott Long bzero(sc->mfi_frames, framessz);
6602e21a3efSScott Long bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
6610d9a4ef3SDoug Ambrisko sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0);
6622e21a3efSScott Long /*
6632e21a3efSScott Long * Allocate DMA memory for the frame sense data. Keep them in the
6642e21a3efSScott Long * lower 4GB for efficiency
6652e21a3efSScott Long */
6662e21a3efSScott Long sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN;
6672e21a3efSScott Long if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
6682e21a3efSScott Long 4, 0, /* algnmnt, boundary */
6692e21a3efSScott Long BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
6702e21a3efSScott Long BUS_SPACE_MAXADDR, /* highaddr */
6712e21a3efSScott Long NULL, NULL, /* filter, filterarg */
6722e21a3efSScott Long sensesz, /* maxsize */
6732e21a3efSScott Long 1, /* nsegments */
6742e21a3efSScott Long sensesz, /* maxsegsize */
6752e21a3efSScott Long 0, /* flags */
6762e21a3efSScott Long NULL, NULL, /* lockfunc, lockarg */
6772e21a3efSScott Long &sc->mfi_sense_dmat)) {
6782e21a3efSScott Long device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n");
6792e21a3efSScott Long return (ENOMEM);
6802e21a3efSScott Long }
6812e21a3efSScott Long if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense,
6822e21a3efSScott Long BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) {
6832e21a3efSScott Long device_printf(sc->mfi_dev, "Cannot allocate sense memory\n");
6842e21a3efSScott Long return (ENOMEM);
6852e21a3efSScott Long }
6862e21a3efSScott Long bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
6870d9a4ef3SDoug Ambrisko sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0);
6882e21a3efSScott Long if ((error = mfi_alloc_commands(sc)) != 0)
6892e21a3efSScott Long return (error);
6902e21a3efSScott Long
6910d9a4ef3SDoug Ambrisko /* Before moving the FW to operational state, check whether
6920d9a4ef3SDoug Ambrisko * hostmemory is required by the FW or not
6932e21a3efSScott Long */
6940d9a4ef3SDoug Ambrisko
6950d9a4ef3SDoug Ambrisko /* ThunderBolt MFI_IOC2 INIT */
696a6ba0fd6SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
6970d9a4ef3SDoug Ambrisko sc->mfi_disable_intr(sc);
69808c89430SSteven Hartland mtx_lock(&sc->mfi_io_lock);
699a6ba0fd6SDoug Ambrisko if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) {
700a6ba0fd6SDoug Ambrisko device_printf(sc->mfi_dev,
701a6ba0fd6SDoug Ambrisko "TB Init has failed with error %d\n",error);
70208c89430SSteven Hartland mtx_unlock(&sc->mfi_io_lock);
7030d9a4ef3SDoug Ambrisko return error;
7040d9a4ef3SDoug Ambrisko }
70508c89430SSteven Hartland mtx_unlock(&sc->mfi_io_lock);
7060d9a4ef3SDoug Ambrisko
7070d9a4ef3SDoug Ambrisko if ((error = mfi_tbolt_alloc_cmd(sc)) != 0)
7080d9a4ef3SDoug Ambrisko return error;
709a6ba0fd6SDoug Ambrisko if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
710a6ba0fd6SDoug Ambrisko INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc,
711a6ba0fd6SDoug Ambrisko &sc->mfi_intr)) {
7122e21a3efSScott Long device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
7132e21a3efSScott Long return (EINVAL);
7142e21a3efSScott Long }
71558ef3154SDoug Ambrisko sc->mfi_intr_ptr = mfi_intr_tbolt;
7160d9a4ef3SDoug Ambrisko sc->mfi_enable_intr(sc);
717a6ba0fd6SDoug Ambrisko } else {
7182e21a3efSScott Long if ((error = mfi_comms_init(sc)) != 0)
7192e21a3efSScott Long return (error);
7202e21a3efSScott Long
721a6ba0fd6SDoug Ambrisko if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
722a6ba0fd6SDoug Ambrisko INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) {
7232e21a3efSScott Long device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
7242e21a3efSScott Long return (EINVAL);
7252e21a3efSScott Long }
72658ef3154SDoug Ambrisko sc->mfi_intr_ptr = mfi_intr;
7270d9a4ef3SDoug Ambrisko sc->mfi_enable_intr(sc);
7280d9a4ef3SDoug Ambrisko }
7290d9a4ef3SDoug Ambrisko if ((error = mfi_get_controller_info(sc)) != 0)
7300d9a4ef3SDoug Ambrisko return (error);
7310d9a4ef3SDoug Ambrisko sc->disableOnlineCtrlReset = 0;
7322e21a3efSScott Long
7332e21a3efSScott Long /* Register a config hook to probe the bus for arrays */
7342e21a3efSScott Long sc->mfi_ich.ich_func = mfi_startup;
7352e21a3efSScott Long sc->mfi_ich.ich_arg = sc;
7362e21a3efSScott Long if (config_intrhook_establish(&sc->mfi_ich) != 0) {
7372e21a3efSScott Long device_printf(sc->mfi_dev, "Cannot establish configuration "
7382e21a3efSScott Long "hook\n");
7392e21a3efSScott Long return (EINVAL);
7402e21a3efSScott Long }
74108c89430SSteven Hartland mtx_lock(&sc->mfi_io_lock);
74208c89430SSteven Hartland if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
74308c89430SSteven Hartland mtx_unlock(&sc->mfi_io_lock);
7440d9a4ef3SDoug Ambrisko return (error);
74508c89430SSteven Hartland }
74608c89430SSteven Hartland mtx_unlock(&sc->mfi_io_lock);
7472e21a3efSScott Long
7482e21a3efSScott Long /*
7492e21a3efSScott Long * Register a shutdown handler.
7502e21a3efSScott Long */
7512e21a3efSScott Long if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown,
7522e21a3efSScott Long sc, SHUTDOWN_PRI_DEFAULT)) == NULL) {
7532e21a3efSScott Long device_printf(sc->mfi_dev, "Warning: shutdown event "
7542e21a3efSScott Long "registration failed\n");
7552e21a3efSScott Long }
7562e21a3efSScott Long
7572e21a3efSScott Long /*
7582e21a3efSScott Long * Create the control device for doing management
7592e21a3efSScott Long */
7602e21a3efSScott Long unit = device_get_unit(sc->mfi_dev);
7612e21a3efSScott Long sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR,
7622e21a3efSScott Long 0640, "mfi%d", unit);
763741367d5SDoug Ambrisko if (unit == 0)
764b5c50320SDoug Ambrisko make_dev_alias_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &dev_t,
765b5c50320SDoug Ambrisko sc->mfi_cdev, "%s", "megaraid_sas_ioctl_node");
7662e21a3efSScott Long if (sc->mfi_cdev != NULL)
7672e21a3efSScott Long sc->mfi_cdev->si_drv1 = sc;
7688ec5c98bSJohn Baldwin SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
7698ec5c98bSJohn Baldwin SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
7708ec5c98bSJohn Baldwin OID_AUTO, "delete_busy_volumes", CTLFLAG_RW,
7718ec5c98bSJohn Baldwin &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes");
7728ec5c98bSJohn Baldwin SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev),
7738ec5c98bSJohn Baldwin SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)),
7748ec5c98bSJohn Baldwin OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW,
7758ec5c98bSJohn Baldwin &sc->mfi_keep_deleted_volumes, 0,
7768ec5c98bSJohn Baldwin "Don't detach the mfid device for a busy volume that is deleted");
7772e21a3efSScott Long
7785b56413dSWarner Losh device_add_child(sc->mfi_dev, "mfip", DEVICE_UNIT_ANY);
77918250ec6SJohn Baldwin bus_attach_children(sc->mfi_dev);
78035ef86f2SScott Long
7815ba21ff1SScott Long /* Start the timeout watchdog */
782fd90e2edSJung-uk Kim callout_init(&sc->mfi_watchdog_callout, 1);
783f108bdaaSSteven Hartland callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz,
7845ba21ff1SScott Long mfi_timeout, sc);
7855ba21ff1SScott Long
786ddbffe7fSDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
78708c89430SSteven Hartland mtx_lock(&sc->mfi_io_lock);
788ddbffe7fSDoug Ambrisko mfi_tbolt_sync_map_info(sc);
78908c89430SSteven Hartland mtx_unlock(&sc->mfi_io_lock);
790ddbffe7fSDoug Ambrisko }
791ddbffe7fSDoug Ambrisko
7922e21a3efSScott Long return (0);
7932e21a3efSScott Long }
7942e21a3efSScott Long
7952e21a3efSScott Long static int
mfi_alloc_commands(struct mfi_softc * sc)7962e21a3efSScott Long mfi_alloc_commands(struct mfi_softc *sc)
7972e21a3efSScott Long {
7982e21a3efSScott Long struct mfi_command *cm;
79908c89430SSteven Hartland int i, j;
8002e21a3efSScott Long
8012e21a3efSScott Long /*
8022e21a3efSScott Long * XXX Should we allocate all the commands up front, or allocate on
8032e21a3efSScott Long * demand later like 'aac' does?
8042e21a3efSScott Long */
80508c89430SSteven Hartland sc->mfi_commands = malloc(sizeof(sc->mfi_commands[0]) *
80608c89430SSteven Hartland sc->mfi_max_fw_cmds, M_MFIBUF, M_WAITOK | M_ZERO);
8070929b669SScott Long
80808c89430SSteven Hartland for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
8092e21a3efSScott Long cm = &sc->mfi_commands[i];
8102e21a3efSScott Long cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames +
81178e36c27SScott Long sc->mfi_cmd_size * i);
8122e21a3efSScott Long cm->cm_frame_busaddr = sc->mfi_frames_busaddr +
81378e36c27SScott Long sc->mfi_cmd_size * i;
8142e21a3efSScott Long cm->cm_frame->header.context = i;
8152e21a3efSScott Long cm->cm_sense = &sc->mfi_sense[i];
8162e21a3efSScott Long cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i;
8172e21a3efSScott Long cm->cm_sc = sc;
8185ba21ff1SScott Long cm->cm_index = i;
8192e21a3efSScott Long if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
8200d9a4ef3SDoug Ambrisko &cm->cm_dmamap) == 0) {
8210d9a4ef3SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
8222e21a3efSScott Long mfi_release_command(cm);
8230d9a4ef3SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
82408c89430SSteven Hartland } else {
82508c89430SSteven Hartland device_printf(sc->mfi_dev, "Failed to allocate %d "
82608c89430SSteven Hartland "command blocks, only allocated %d\n",
82708c89430SSteven Hartland sc->mfi_max_fw_cmds, i - 1);
82808c89430SSteven Hartland for (j = 0; j < i; j++) {
82908c89430SSteven Hartland cm = &sc->mfi_commands[i];
83008c89430SSteven Hartland bus_dmamap_destroy(sc->mfi_buffer_dmat,
83108c89430SSteven Hartland cm->cm_dmamap);
8320d9a4ef3SDoug Ambrisko }
83308c89430SSteven Hartland free(sc->mfi_commands, M_MFIBUF);
83408c89430SSteven Hartland sc->mfi_commands = NULL;
83508c89430SSteven Hartland
83608c89430SSteven Hartland return (ENOMEM);
83708c89430SSteven Hartland }
8382e21a3efSScott Long }
8392e21a3efSScott Long
8402e21a3efSScott Long return (0);
8412e21a3efSScott Long }
8422e21a3efSScott Long
84335ef86f2SScott Long void
mfi_release_command(struct mfi_command * cm)8442e21a3efSScott Long mfi_release_command(struct mfi_command *cm)
8452e21a3efSScott Long {
846441f6d5dSScott Long struct mfi_frame_header *hdr;
8472e21a3efSScott Long uint32_t *hdr_data;
8482e21a3efSScott Long
8490d9a4ef3SDoug Ambrisko mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED);
8500d9a4ef3SDoug Ambrisko
8512e21a3efSScott Long /*
8522e21a3efSScott Long * Zero out the important fields of the frame, but make sure the
853a91d6dabSScott Long * context field is preserved. For efficiency, handle the fields
854a91d6dabSScott Long * as 32 bit words. Clear out the first S/G entry too for safety.
8552e21a3efSScott Long */
856441f6d5dSScott Long hdr = &cm->cm_frame->header;
85704697de9SDoug Ambrisko if (cm->cm_data != NULL && hdr->sg_count) {
858441f6d5dSScott Long cm->cm_sg->sg32[0].len = 0;
859441f6d5dSScott Long cm->cm_sg->sg32[0].addr = 0;
860441f6d5dSScott Long }
861a91d6dabSScott Long
86208c89430SSteven Hartland /*
86308c89430SSteven Hartland * Command may be on other queues e.g. busy queue depending on the
86408c89430SSteven Hartland * flow of a previous call to mfi_mapcmd, so ensure its dequeued
86508c89430SSteven Hartland * properly
86608c89430SSteven Hartland */
86708c89430SSteven Hartland if ((cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0)
86808c89430SSteven Hartland mfi_remove_busy(cm);
86908c89430SSteven Hartland if ((cm->cm_flags & MFI_ON_MFIQ_READY) != 0)
87008c89430SSteven Hartland mfi_remove_ready(cm);
87108c89430SSteven Hartland
87208c89430SSteven Hartland /* We're not expecting it to be on any other queue but check */
87308c89430SSteven Hartland if ((cm->cm_flags & MFI_ON_MFIQ_MASK) != 0) {
87408c89430SSteven Hartland panic("Command %p is still on another queue, flags = %#x",
87508c89430SSteven Hartland cm, cm->cm_flags);
87608c89430SSteven Hartland }
87708c89430SSteven Hartland
87808c89430SSteven Hartland /* tbolt cleanup */
87908c89430SSteven Hartland if ((cm->cm_flags & MFI_CMD_TBOLT) != 0) {
88008c89430SSteven Hartland mfi_tbolt_return_cmd(cm->cm_sc,
88108c89430SSteven Hartland cm->cm_sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames - 1],
88208c89430SSteven Hartland cm);
88308c89430SSteven Hartland }
88408c89430SSteven Hartland
885a91d6dabSScott Long hdr_data = (uint32_t *)cm->cm_frame;
886a91d6dabSScott Long hdr_data[0] = 0; /* cmd, sense_len, cmd_status, scsi_status */
887a91d6dabSScott Long hdr_data[1] = 0; /* target_id, lun_id, cdb_len, sg_count */
888a91d6dabSScott Long hdr_data[4] = 0; /* flags, timeout */
889a91d6dabSScott Long hdr_data[5] = 0; /* data_len */
890a91d6dabSScott Long
8912e21a3efSScott Long cm->cm_extra_frames = 0;
8922e21a3efSScott Long cm->cm_flags = 0;
8932e21a3efSScott Long cm->cm_complete = NULL;
8942e21a3efSScott Long cm->cm_private = NULL;
89535ef86f2SScott Long cm->cm_data = NULL;
8962e21a3efSScott Long cm->cm_sg = 0;
8972e21a3efSScott Long cm->cm_total_frame_size = 0;
8980d9a4ef3SDoug Ambrisko cm->retry_for_fw_reset = 0;
899441f6d5dSScott Long
9002e21a3efSScott Long mfi_enqueue_free(cm);
9012e21a3efSScott Long }
9022e21a3efSScott Long
903ddbffe7fSDoug Ambrisko int
mfi_dcmd_command(struct mfi_softc * sc,struct mfi_command ** cmp,uint32_t opcode,void ** bufp,size_t bufsize)904a6ba0fd6SDoug Ambrisko mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp,
905a6ba0fd6SDoug Ambrisko uint32_t opcode, void **bufp, size_t bufsize)
906fb595e7aSPaul Saab {
907fb595e7aSPaul Saab struct mfi_command *cm;
908fb595e7aSPaul Saab struct mfi_dcmd_frame *dcmd;
909fb595e7aSPaul Saab void *buf = NULL;
9100d9a4ef3SDoug Ambrisko uint32_t context = 0;
911fb595e7aSPaul Saab
912fb595e7aSPaul Saab mtx_assert(&sc->mfi_io_lock, MA_OWNED);
913fb595e7aSPaul Saab
914fb595e7aSPaul Saab cm = mfi_dequeue_free(sc);
915fb595e7aSPaul Saab if (cm == NULL)
916fb595e7aSPaul Saab return (EBUSY);
917fb595e7aSPaul Saab
9180d9a4ef3SDoug Ambrisko /* Zero out the MFI frame */
9190d9a4ef3SDoug Ambrisko context = cm->cm_frame->header.context;
9200d9a4ef3SDoug Ambrisko bzero(cm->cm_frame, sizeof(union mfi_frame));
9210d9a4ef3SDoug Ambrisko cm->cm_frame->header.context = context;
9220d9a4ef3SDoug Ambrisko
923fb595e7aSPaul Saab if ((bufsize > 0) && (bufp != NULL)) {
924fb595e7aSPaul Saab if (*bufp == NULL) {
925fb595e7aSPaul Saab buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
926fb595e7aSPaul Saab if (buf == NULL) {
927fb595e7aSPaul Saab mfi_release_command(cm);
928fb595e7aSPaul Saab return (ENOMEM);
929fb595e7aSPaul Saab }
930fb595e7aSPaul Saab *bufp = buf;
931fb595e7aSPaul Saab } else {
932fb595e7aSPaul Saab buf = *bufp;
933fb595e7aSPaul Saab }
934fb595e7aSPaul Saab }
935fb595e7aSPaul Saab
936fb595e7aSPaul Saab dcmd = &cm->cm_frame->dcmd;
937fb595e7aSPaul Saab bzero(dcmd->mbox, MFI_MBOX_SIZE);
938fb595e7aSPaul Saab dcmd->header.cmd = MFI_CMD_DCMD;
939fb595e7aSPaul Saab dcmd->header.timeout = 0;
940fb595e7aSPaul Saab dcmd->header.flags = 0;
941fb595e7aSPaul Saab dcmd->header.data_len = bufsize;
9420d9a4ef3SDoug Ambrisko dcmd->header.scsi_status = 0;
943fb595e7aSPaul Saab dcmd->opcode = opcode;
944fb595e7aSPaul Saab cm->cm_sg = &dcmd->sgl;
945fb595e7aSPaul Saab cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
946fb595e7aSPaul Saab cm->cm_flags = 0;
947fb595e7aSPaul Saab cm->cm_data = buf;
948fb595e7aSPaul Saab cm->cm_private = buf;
949fb595e7aSPaul Saab cm->cm_len = bufsize;
950fb595e7aSPaul Saab
951fb595e7aSPaul Saab *cmp = cm;
952fb595e7aSPaul Saab if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
953fb595e7aSPaul Saab *bufp = buf;
954fb595e7aSPaul Saab return (0);
955fb595e7aSPaul Saab }
956fb595e7aSPaul Saab
957fb595e7aSPaul Saab static int
mfi_comms_init(struct mfi_softc * sc)9582e21a3efSScott Long mfi_comms_init(struct mfi_softc *sc)
9592e21a3efSScott Long {
9602e21a3efSScott Long struct mfi_command *cm;
9612e21a3efSScott Long struct mfi_init_frame *init;
9622e21a3efSScott Long struct mfi_init_qinfo *qinfo;
9632e21a3efSScott Long int error;
9640d9a4ef3SDoug Ambrisko uint32_t context = 0;
9652e21a3efSScott Long
966441f6d5dSScott Long mtx_lock(&sc->mfi_io_lock);
96708c89430SSteven Hartland if ((cm = mfi_dequeue_free(sc)) == NULL) {
96808c89430SSteven Hartland mtx_unlock(&sc->mfi_io_lock);
9692e21a3efSScott Long return (EBUSY);
97008c89430SSteven Hartland }
9712e21a3efSScott Long
9720d9a4ef3SDoug Ambrisko /* Zero out the MFI frame */
9730d9a4ef3SDoug Ambrisko context = cm->cm_frame->header.context;
9740d9a4ef3SDoug Ambrisko bzero(cm->cm_frame, sizeof(union mfi_frame));
9750d9a4ef3SDoug Ambrisko cm->cm_frame->header.context = context;
9760d9a4ef3SDoug Ambrisko
9772e21a3efSScott Long /*
9782e21a3efSScott Long * Abuse the SG list area of the frame to hold the init_qinfo
9792e21a3efSScott Long * object;
9802e21a3efSScott Long */
9812e21a3efSScott Long init = &cm->cm_frame->init;
9822e21a3efSScott Long qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE);
9832e21a3efSScott Long
9842e21a3efSScott Long bzero(qinfo, sizeof(struct mfi_init_qinfo));
9852e21a3efSScott Long qinfo->rq_entries = sc->mfi_max_fw_cmds + 1;
9862e21a3efSScott Long qinfo->rq_addr_lo = sc->mfi_comms_busaddr +
9872e21a3efSScott Long offsetof(struct mfi_hwcomms, hw_reply_q);
9882e21a3efSScott Long qinfo->pi_addr_lo = sc->mfi_comms_busaddr +
9892e21a3efSScott Long offsetof(struct mfi_hwcomms, hw_pi);
9902e21a3efSScott Long qinfo->ci_addr_lo = sc->mfi_comms_busaddr +
9912e21a3efSScott Long offsetof(struct mfi_hwcomms, hw_ci);
9922e21a3efSScott Long
9932e21a3efSScott Long init->header.cmd = MFI_CMD_INIT;
9942e21a3efSScott Long init->header.data_len = sizeof(struct mfi_init_qinfo);
9952e21a3efSScott Long init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE;
9963c77cee1SScott Long cm->cm_data = NULL;
9973c77cee1SScott Long cm->cm_flags = MFI_CMD_POLLED;
9982e21a3efSScott Long
99908c89430SSteven Hartland if ((error = mfi_mapcmd(sc, cm)) != 0)
10002e21a3efSScott Long device_printf(sc->mfi_dev, "failed to send init command\n");
10012e21a3efSScott Long mfi_release_command(cm);
1002441f6d5dSScott Long mtx_unlock(&sc->mfi_io_lock);
10032e21a3efSScott Long
100408c89430SSteven Hartland return (error);
10052e21a3efSScott Long }
10062e21a3efSScott Long
10072e21a3efSScott Long static int
mfi_get_controller_info(struct mfi_softc * sc)10082e21a3efSScott Long mfi_get_controller_info(struct mfi_softc *sc)
10092e21a3efSScott Long {
1010fb595e7aSPaul Saab struct mfi_command *cm = NULL;
1011fb595e7aSPaul Saab struct mfi_ctrl_info *ci = NULL;
10122e21a3efSScott Long uint32_t max_sectors_1, max_sectors_2;
10132e21a3efSScott Long int error;
10142e21a3efSScott Long
1015fb595e7aSPaul Saab mtx_lock(&sc->mfi_io_lock);
1016fb595e7aSPaul Saab error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO,
1017fb595e7aSPaul Saab (void **)&ci, sizeof(*ci));
1018fb595e7aSPaul Saab if (error)
1019fb595e7aSPaul Saab goto out;
10202e21a3efSScott Long cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
10212e21a3efSScott Long
10222e21a3efSScott Long if ((error = mfi_mapcmd(sc, cm)) != 0) {
10232e21a3efSScott Long device_printf(sc->mfi_dev, "Failed to get controller info\n");
102478e36c27SScott Long sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE /
10252e21a3efSScott Long MFI_SECTOR_LEN;
1026fb595e7aSPaul Saab error = 0;
1027fb595e7aSPaul Saab goto out;
10282e21a3efSScott Long }
10292e21a3efSScott Long
10302e21a3efSScott Long bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
10312e21a3efSScott Long BUS_DMASYNC_POSTREAD);
10322e21a3efSScott Long bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
10332e21a3efSScott Long
10340d9a4ef3SDoug Ambrisko max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io;
10352e21a3efSScott Long max_sectors_2 = ci->max_request_size;
10362e21a3efSScott Long sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
1037a6ba0fd6SDoug Ambrisko sc->disableOnlineCtrlReset =
1038a6ba0fd6SDoug Ambrisko ci->properties.OnOffProperties.disableOnlineCtrlReset;
10392e21a3efSScott Long
1040fb595e7aSPaul Saab out:
1041fb595e7aSPaul Saab if (ci)
10422e21a3efSScott Long free(ci, M_MFIBUF);
1043fb595e7aSPaul Saab if (cm)
10442e21a3efSScott Long mfi_release_command(cm);
1045fb595e7aSPaul Saab mtx_unlock(&sc->mfi_io_lock);
10462e21a3efSScott Long return (error);
10472e21a3efSScott Long }
10482e21a3efSScott Long
10492e21a3efSScott Long static int
mfi_get_log_state(struct mfi_softc * sc,struct mfi_evt_log_state ** log_state)1050fb595e7aSPaul Saab mfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
1051741367d5SDoug Ambrisko {
1052e94bb9b2SPaul Saab struct mfi_command *cm = NULL;
1053741367d5SDoug Ambrisko int error;
1054741367d5SDoug Ambrisko
105508c89430SSteven Hartland mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1056fb595e7aSPaul Saab error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
1057fb595e7aSPaul Saab (void **)log_state, sizeof(**log_state));
1058fb595e7aSPaul Saab if (error)
1059fb595e7aSPaul Saab goto out;
1060330df1acSPaul Saab cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
1061741367d5SDoug Ambrisko
1062741367d5SDoug Ambrisko if ((error = mfi_mapcmd(sc, cm)) != 0) {
106383ff9c13SPaul Saab device_printf(sc->mfi_dev, "Failed to get log state\n");
1064fb595e7aSPaul Saab goto out;
1065741367d5SDoug Ambrisko }
1066741367d5SDoug Ambrisko
1067741367d5SDoug Ambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1068741367d5SDoug Ambrisko BUS_DMASYNC_POSTREAD);
1069741367d5SDoug Ambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1070741367d5SDoug Ambrisko
1071fb595e7aSPaul Saab out:
1072e94bb9b2SPaul Saab if (cm)
1073741367d5SDoug Ambrisko mfi_release_command(cm);
1074741367d5SDoug Ambrisko
1075741367d5SDoug Ambrisko return (error);
1076741367d5SDoug Ambrisko }
1077741367d5SDoug Ambrisko
10780d9a4ef3SDoug Ambrisko int
mfi_aen_setup(struct mfi_softc * sc,uint32_t seq_start)1079741367d5SDoug Ambrisko mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
1080741367d5SDoug Ambrisko {
1081fb595e7aSPaul Saab struct mfi_evt_log_state *log_state = NULL;
1082741367d5SDoug Ambrisko union mfi_evt class_locale;
1083741367d5SDoug Ambrisko int error = 0;
1084741367d5SDoug Ambrisko uint32_t seq;
1085741367d5SDoug Ambrisko
108608c89430SSteven Hartland mtx_assert(&sc->mfi_io_lock, MA_OWNED);
108708c89430SSteven Hartland
1088741367d5SDoug Ambrisko class_locale.members.reserved = 0;
108947b470b9SDoug Ambrisko class_locale.members.locale = mfi_event_locale;
1090aacea6e2SEd Maste class_locale.members.evt_class = mfi_event_class;
1091741367d5SDoug Ambrisko
1092741367d5SDoug Ambrisko if (seq_start == 0) {
109308c89430SSteven Hartland if ((error = mfi_get_log_state(sc, &log_state)) != 0)
109408c89430SSteven Hartland goto out;
1095a6ba0fd6SDoug Ambrisko sc->mfi_boot_seq_num = log_state->boot_seq_num;
1096c1ed06a8SJohn Baldwin
1097c1ed06a8SJohn Baldwin /*
1098c1ed06a8SJohn Baldwin * Walk through any events that fired since the last
1099c1ed06a8SJohn Baldwin * shutdown.
1100c1ed06a8SJohn Baldwin */
110108c89430SSteven Hartland if ((error = mfi_parse_entries(sc, log_state->shutdown_seq_num,
110208c89430SSteven Hartland log_state->newest_seq_num)) != 0)
110308c89430SSteven Hartland goto out;
1104c1ed06a8SJohn Baldwin seq = log_state->newest_seq_num;
1105741367d5SDoug Ambrisko } else
1106741367d5SDoug Ambrisko seq = seq_start;
110708c89430SSteven Hartland error = mfi_aen_register(sc, seq, class_locale.word);
110808c89430SSteven Hartland out:
1109fb595e7aSPaul Saab free(log_state, M_MFIBUF);
1110741367d5SDoug Ambrisko
111108c89430SSteven Hartland return (error);
1112741367d5SDoug Ambrisko }
1113741367d5SDoug Ambrisko
11140d9a4ef3SDoug Ambrisko int
mfi_wait_command(struct mfi_softc * sc,struct mfi_command * cm)1115c0b332d1SPaul Saab mfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
1116c0b332d1SPaul Saab {
1117c0b332d1SPaul Saab
1118c0b332d1SPaul Saab mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1119c0b332d1SPaul Saab cm->cm_complete = NULL;
1120c0b332d1SPaul Saab
11215be25877SDoug Ambrisko /*
11225be25877SDoug Ambrisko * MegaCli can issue a DCMD of 0. In this case do nothing
11235be25877SDoug Ambrisko * and return 0 to it as status
11245be25877SDoug Ambrisko */
11255be25877SDoug Ambrisko if (cm->cm_frame->dcmd.opcode == 0) {
11265be25877SDoug Ambrisko cm->cm_frame->header.cmd_status = MFI_STAT_OK;
11275be25877SDoug Ambrisko cm->cm_error = 0;
11285be25877SDoug Ambrisko return (cm->cm_error);
11295be25877SDoug Ambrisko }
1130c0b332d1SPaul Saab mfi_enqueue_ready(cm);
1131c0b332d1SPaul Saab mfi_startio(sc);
11325be25877SDoug Ambrisko if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0)
11335be25877SDoug Ambrisko msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0);
11345be25877SDoug Ambrisko return (cm->cm_error);
1135c0b332d1SPaul Saab }
1136c0b332d1SPaul Saab
11372e21a3efSScott Long void
mfi_free(struct mfi_softc * sc)11382e21a3efSScott Long mfi_free(struct mfi_softc *sc)
11392e21a3efSScott Long {
11402e21a3efSScott Long struct mfi_command *cm;
11412e21a3efSScott Long int i;
11422e21a3efSScott Long
11435ba21ff1SScott Long callout_drain(&sc->mfi_watchdog_callout);
11445ba21ff1SScott Long
11452e21a3efSScott Long if (sc->mfi_cdev != NULL)
11462e21a3efSScott Long destroy_dev(sc->mfi_cdev);
11472e21a3efSScott Long
114808c89430SSteven Hartland if (sc->mfi_commands != NULL) {
114908c89430SSteven Hartland for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
11502e21a3efSScott Long cm = &sc->mfi_commands[i];
11512e21a3efSScott Long bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap);
11522e21a3efSScott Long }
11532e21a3efSScott Long free(sc->mfi_commands, M_MFIBUF);
115408c89430SSteven Hartland sc->mfi_commands = NULL;
11552e21a3efSScott Long }
11562e21a3efSScott Long
11572e21a3efSScott Long if (sc->mfi_intr)
11582e21a3efSScott Long bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr);
11592e21a3efSScott Long if (sc->mfi_irq != NULL)
11602e21a3efSScott Long bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid,
11612e21a3efSScott Long sc->mfi_irq);
11622e21a3efSScott Long
11632e21a3efSScott Long if (sc->mfi_sense_busaddr != 0)
11642e21a3efSScott Long bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap);
11652e21a3efSScott Long if (sc->mfi_sense != NULL)
11662e21a3efSScott Long bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense,
11672e21a3efSScott Long sc->mfi_sense_dmamap);
11682e21a3efSScott Long if (sc->mfi_sense_dmat != NULL)
11692e21a3efSScott Long bus_dma_tag_destroy(sc->mfi_sense_dmat);
11702e21a3efSScott Long
11712e21a3efSScott Long if (sc->mfi_frames_busaddr != 0)
11722e21a3efSScott Long bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap);
11732e21a3efSScott Long if (sc->mfi_frames != NULL)
11742e21a3efSScott Long bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames,
11752e21a3efSScott Long sc->mfi_frames_dmamap);
11762e21a3efSScott Long if (sc->mfi_frames_dmat != NULL)
11772e21a3efSScott Long bus_dma_tag_destroy(sc->mfi_frames_dmat);
11782e21a3efSScott Long
11792e21a3efSScott Long if (sc->mfi_comms_busaddr != 0)
11802e21a3efSScott Long bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap);
11812e21a3efSScott Long if (sc->mfi_comms != NULL)
11822e21a3efSScott Long bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms,
11832e21a3efSScott Long sc->mfi_comms_dmamap);
11842e21a3efSScott Long if (sc->mfi_comms_dmat != NULL)
11852e21a3efSScott Long bus_dma_tag_destroy(sc->mfi_comms_dmat);
11862e21a3efSScott Long
11870d9a4ef3SDoug Ambrisko /* ThunderBolt contiguous memory free here */
1188a6ba0fd6SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
11890d9a4ef3SDoug Ambrisko if (sc->mfi_tb_busaddr != 0)
11900d9a4ef3SDoug Ambrisko bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap);
11910d9a4ef3SDoug Ambrisko if (sc->request_message_pool != NULL)
11920d9a4ef3SDoug Ambrisko bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool,
11930d9a4ef3SDoug Ambrisko sc->mfi_tb_dmamap);
11940d9a4ef3SDoug Ambrisko if (sc->mfi_tb_dmat != NULL)
11950d9a4ef3SDoug Ambrisko bus_dma_tag_destroy(sc->mfi_tb_dmat);
11960d9a4ef3SDoug Ambrisko
11970d9a4ef3SDoug Ambrisko /* Version buffer memory free */
1198a6ba0fd6SDoug Ambrisko /* Start LSIP200113393 */
11990d9a4ef3SDoug Ambrisko if (sc->verbuf_h_busaddr != 0)
12000d9a4ef3SDoug Ambrisko bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap);
12010d9a4ef3SDoug Ambrisko if (sc->verbuf != NULL)
12020d9a4ef3SDoug Ambrisko bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf,
12030d9a4ef3SDoug Ambrisko sc->verbuf_h_dmamap);
12040d9a4ef3SDoug Ambrisko if (sc->verbuf_h_dmat != NULL)
12050d9a4ef3SDoug Ambrisko bus_dma_tag_destroy(sc->verbuf_h_dmat);
12060d9a4ef3SDoug Ambrisko
1207a6ba0fd6SDoug Ambrisko /* End LSIP200113393 */
1208a6ba0fd6SDoug Ambrisko /* ThunderBolt INIT packet memory Free */
12090d9a4ef3SDoug Ambrisko if (sc->mfi_tb_init_busaddr != 0)
121008c89430SSteven Hartland bus_dmamap_unload(sc->mfi_tb_init_dmat,
121108c89430SSteven Hartland sc->mfi_tb_init_dmamap);
12120d9a4ef3SDoug Ambrisko if (sc->mfi_tb_init != NULL)
12130d9a4ef3SDoug Ambrisko bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init,
12140d9a4ef3SDoug Ambrisko sc->mfi_tb_init_dmamap);
12150d9a4ef3SDoug Ambrisko if (sc->mfi_tb_init_dmat != NULL)
12160d9a4ef3SDoug Ambrisko bus_dma_tag_destroy(sc->mfi_tb_init_dmat);
12170d9a4ef3SDoug Ambrisko
12180d9a4ef3SDoug Ambrisko /* ThunderBolt IOC Init Desc memory free here */
12190d9a4ef3SDoug Ambrisko if (sc->mfi_tb_ioc_init_busaddr != 0)
1220a6ba0fd6SDoug Ambrisko bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat,
1221a6ba0fd6SDoug Ambrisko sc->mfi_tb_ioc_init_dmamap);
12220d9a4ef3SDoug Ambrisko if (sc->mfi_tb_ioc_init_desc != NULL)
1223a6ba0fd6SDoug Ambrisko bus_dmamem_free(sc->mfi_tb_ioc_init_dmat,
1224a6ba0fd6SDoug Ambrisko sc->mfi_tb_ioc_init_desc,
1225a6ba0fd6SDoug Ambrisko sc->mfi_tb_ioc_init_dmamap);
12260d9a4ef3SDoug Ambrisko if (sc->mfi_tb_ioc_init_dmat != NULL)
12270d9a4ef3SDoug Ambrisko bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat);
1228a6ba0fd6SDoug Ambrisko if (sc->mfi_cmd_pool_tbolt != NULL) {
122908c89430SSteven Hartland for (int i = 0; i < sc->mfi_max_fw_cmds; i++) {
1230a6ba0fd6SDoug Ambrisko if (sc->mfi_cmd_pool_tbolt[i] != NULL) {
1231a6ba0fd6SDoug Ambrisko free(sc->mfi_cmd_pool_tbolt[i],
1232a6ba0fd6SDoug Ambrisko M_MFIBUF);
12330d9a4ef3SDoug Ambrisko sc->mfi_cmd_pool_tbolt[i] = NULL;
12340d9a4ef3SDoug Ambrisko }
12350d9a4ef3SDoug Ambrisko }
12360d9a4ef3SDoug Ambrisko free(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
12370d9a4ef3SDoug Ambrisko sc->mfi_cmd_pool_tbolt = NULL;
12380d9a4ef3SDoug Ambrisko }
1239a6ba0fd6SDoug Ambrisko if (sc->request_desc_pool != NULL) {
12400d9a4ef3SDoug Ambrisko free(sc->request_desc_pool, M_MFIBUF);
12410d9a4ef3SDoug Ambrisko sc->request_desc_pool = NULL;
12420d9a4ef3SDoug Ambrisko }
12430d9a4ef3SDoug Ambrisko }
12442e21a3efSScott Long if (sc->mfi_buffer_dmat != NULL)
12452e21a3efSScott Long bus_dma_tag_destroy(sc->mfi_buffer_dmat);
12462e21a3efSScott Long if (sc->mfi_parent_dmat != NULL)
12472e21a3efSScott Long bus_dma_tag_destroy(sc->mfi_parent_dmat);
12482e21a3efSScott Long
12498ec5c98bSJohn Baldwin if (mtx_initialized(&sc->mfi_io_lock)) {
12502e21a3efSScott Long mtx_destroy(&sc->mfi_io_lock);
12518ec5c98bSJohn Baldwin sx_destroy(&sc->mfi_config_lock);
12528ec5c98bSJohn Baldwin }
12532e21a3efSScott Long
12542e21a3efSScott Long return;
12552e21a3efSScott Long }
12562e21a3efSScott Long
12572e21a3efSScott Long static void
mfi_startup(void * arg)12582e21a3efSScott Long mfi_startup(void *arg)
12592e21a3efSScott Long {
12602e21a3efSScott Long struct mfi_softc *sc;
12612e21a3efSScott Long
12622e21a3efSScott Long sc = (struct mfi_softc *)arg;
12632e21a3efSScott Long
1264610f2ef3SScott Long sc->mfi_enable_intr(sc);
12658ec5c98bSJohn Baldwin sx_xlock(&sc->mfi_config_lock);
1266441f6d5dSScott Long mtx_lock(&sc->mfi_io_lock);
1267c0b332d1SPaul Saab mfi_ldprobe(sc);
12680d9a4ef3SDoug Ambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY)
12690d9a4ef3SDoug Ambrisko mfi_syspdprobe(sc);
1270441f6d5dSScott Long mtx_unlock(&sc->mfi_io_lock);
12718ec5c98bSJohn Baldwin sx_xunlock(&sc->mfi_config_lock);
12723e0ca40aSScott Long
12733e0ca40aSScott Long config_intrhook_disestablish(&sc->mfi_ich);
12742e21a3efSScott Long }
12752e21a3efSScott Long
12762e21a3efSScott Long static void
mfi_intr(void * arg)12772e21a3efSScott Long mfi_intr(void *arg)
12782e21a3efSScott Long {
12792e21a3efSScott Long struct mfi_softc *sc;
12802e21a3efSScott Long struct mfi_command *cm;
1281610f2ef3SScott Long uint32_t pi, ci, context;
12822e21a3efSScott Long
12832e21a3efSScott Long sc = (struct mfi_softc *)arg;
12842e21a3efSScott Long
1285610f2ef3SScott Long if (sc->mfi_check_clear_intr(sc))
12862e21a3efSScott Long return;
1287441f6d5dSScott Long
1288a6ba0fd6SDoug Ambrisko restart:
12892e21a3efSScott Long pi = sc->mfi_comms->hw_pi;
12902e21a3efSScott Long ci = sc->mfi_comms->hw_ci;
12912e21a3efSScott Long mtx_lock(&sc->mfi_io_lock);
12922e21a3efSScott Long while (ci != pi) {
12932e21a3efSScott Long context = sc->mfi_comms->hw_reply_q[ci];
12945be25877SDoug Ambrisko if (context < sc->mfi_max_fw_cmds) {
12952e21a3efSScott Long cm = &sc->mfi_commands[context];
12962e21a3efSScott Long mfi_remove_busy(cm);
12975be25877SDoug Ambrisko cm->cm_error = 0;
12982e21a3efSScott Long mfi_complete(sc, cm);
12995be25877SDoug Ambrisko }
130008c89430SSteven Hartland if (++ci == (sc->mfi_max_fw_cmds + 1))
13012e21a3efSScott Long ci = 0;
13022e21a3efSScott Long }
13032e21a3efSScott Long
13042e21a3efSScott Long sc->mfi_comms->hw_ci = ci;
13052e21a3efSScott Long
1306441f6d5dSScott Long /* Give defered I/O a chance to run */
1307441f6d5dSScott Long sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
1308441f6d5dSScott Long mfi_startio(sc);
1309441f6d5dSScott Long mtx_unlock(&sc->mfi_io_lock);
1310441f6d5dSScott Long
1311a6ba0fd6SDoug Ambrisko /*
1312a6ba0fd6SDoug Ambrisko * Dummy read to flush the bus; this ensures that the indexes are up
1313a6ba0fd6SDoug Ambrisko * to date. Restart processing if more commands have come it.
1314a6ba0fd6SDoug Ambrisko */
1315a6ba0fd6SDoug Ambrisko (void)sc->mfi_read_fw_status(sc);
1316a6ba0fd6SDoug Ambrisko if (pi != sc->mfi_comms->hw_pi)
1317a6ba0fd6SDoug Ambrisko goto restart;
1318a6ba0fd6SDoug Ambrisko
13192e21a3efSScott Long return;
13202e21a3efSScott Long }
13212e21a3efSScott Long
13222e21a3efSScott Long int
mfi_shutdown(struct mfi_softc * sc)13232e21a3efSScott Long mfi_shutdown(struct mfi_softc *sc)
13242e21a3efSScott Long {
13252e21a3efSScott Long struct mfi_dcmd_frame *dcmd;
13262e21a3efSScott Long struct mfi_command *cm;
13272e21a3efSScott Long int error;
13282e21a3efSScott Long
132908c89430SSteven Hartland if (sc->mfi_aen_cm != NULL) {
133058ef3154SDoug Ambrisko sc->cm_aen_abort = 1;
133158ef3154SDoug Ambrisko mfi_abort(sc, &sc->mfi_aen_cm);
133208c89430SSteven Hartland }
133358ef3154SDoug Ambrisko
133408c89430SSteven Hartland if (sc->mfi_map_sync_cm != NULL) {
133558ef3154SDoug Ambrisko sc->cm_map_abort = 1;
133658ef3154SDoug Ambrisko mfi_abort(sc, &sc->mfi_map_sync_cm);
133708c89430SSteven Hartland }
133858ef3154SDoug Ambrisko
1339fb595e7aSPaul Saab mtx_lock(&sc->mfi_io_lock);
1340fb595e7aSPaul Saab error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0);
1341441f6d5dSScott Long if (error) {
1342fb595e7aSPaul Saab mtx_unlock(&sc->mfi_io_lock);
1343fb595e7aSPaul Saab return (error);
1344441f6d5dSScott Long }
13452e21a3efSScott Long
13462e21a3efSScott Long dcmd = &cm->cm_frame->dcmd;
13472e21a3efSScott Long dcmd->header.flags = MFI_FRAME_DIR_NONE;
13483c77cee1SScott Long cm->cm_flags = MFI_CMD_POLLED;
13493c77cee1SScott Long cm->cm_data = NULL;
13502e21a3efSScott Long
135108c89430SSteven Hartland if ((error = mfi_mapcmd(sc, cm)) != 0)
13522e21a3efSScott Long device_printf(sc->mfi_dev, "Failed to shutdown controller\n");
13532e21a3efSScott Long
1354e94bb9b2SPaul Saab mfi_release_command(cm);
1355441f6d5dSScott Long mtx_unlock(&sc->mfi_io_lock);
13562e21a3efSScott Long return (error);
13572e21a3efSScott Long }
13582e21a3efSScott Long
13592e21a3efSScott Long static void
mfi_syspdprobe(struct mfi_softc * sc)13600d9a4ef3SDoug Ambrisko mfi_syspdprobe(struct mfi_softc *sc)
13610d9a4ef3SDoug Ambrisko {
13620d9a4ef3SDoug Ambrisko struct mfi_frame_header *hdr;
13630d9a4ef3SDoug Ambrisko struct mfi_command *cm = NULL;
13640d9a4ef3SDoug Ambrisko struct mfi_pd_list *pdlist = NULL;
1365a6ba0fd6SDoug Ambrisko struct mfi_system_pd *syspd, *tmp;
136658ef3154SDoug Ambrisko struct mfi_system_pending *syspd_pend;
1367a6ba0fd6SDoug Ambrisko int error, i, found;
13680d9a4ef3SDoug Ambrisko
13690d9a4ef3SDoug Ambrisko sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
13700d9a4ef3SDoug Ambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED);
13710d9a4ef3SDoug Ambrisko /* Add SYSTEM PD's */
13720d9a4ef3SDoug Ambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY,
13730d9a4ef3SDoug Ambrisko (void **)&pdlist, sizeof(*pdlist));
13740d9a4ef3SDoug Ambrisko if (error) {
1375a6ba0fd6SDoug Ambrisko device_printf(sc->mfi_dev,
1376a6ba0fd6SDoug Ambrisko "Error while forming SYSTEM PD list\n");
13770d9a4ef3SDoug Ambrisko goto out;
13780d9a4ef3SDoug Ambrisko }
13790d9a4ef3SDoug Ambrisko
13800d9a4ef3SDoug Ambrisko cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
13810d9a4ef3SDoug Ambrisko cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
13820d9a4ef3SDoug Ambrisko cm->cm_frame->dcmd.mbox[1] = 0;
13830d9a4ef3SDoug Ambrisko if (mfi_mapcmd(sc, cm) != 0) {
1384a6ba0fd6SDoug Ambrisko device_printf(sc->mfi_dev,
1385a6ba0fd6SDoug Ambrisko "Failed to get syspd device listing\n");
13860d9a4ef3SDoug Ambrisko goto out;
13870d9a4ef3SDoug Ambrisko }
13880d9a4ef3SDoug Ambrisko bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap,
13890d9a4ef3SDoug Ambrisko BUS_DMASYNC_POSTREAD);
13900d9a4ef3SDoug Ambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
13910d9a4ef3SDoug Ambrisko hdr = &cm->cm_frame->header;
13920d9a4ef3SDoug Ambrisko if (hdr->cmd_status != MFI_STAT_OK) {
1393a6ba0fd6SDoug Ambrisko device_printf(sc->mfi_dev,
1394a6ba0fd6SDoug Ambrisko "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status);
13950d9a4ef3SDoug Ambrisko goto out;
13960d9a4ef3SDoug Ambrisko }
13970d9a4ef3SDoug Ambrisko /* Get each PD and add it to the system */
1398a6ba0fd6SDoug Ambrisko for (i = 0; i < pdlist->count; i++) {
1399a6ba0fd6SDoug Ambrisko if (pdlist->addr[i].device_id ==
1400a6ba0fd6SDoug Ambrisko pdlist->addr[i].encl_device_id)
1401a6ba0fd6SDoug Ambrisko continue;
1402a6ba0fd6SDoug Ambrisko found = 0;
14030d9a4ef3SDoug Ambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
14040d9a4ef3SDoug Ambrisko if (syspd->pd_id == pdlist->addr[i].device_id)
1405a6ba0fd6SDoug Ambrisko found = 1;
14060d9a4ef3SDoug Ambrisko }
140758ef3154SDoug Ambrisko TAILQ_FOREACH(syspd_pend, &sc->mfi_syspd_pend_tqh, pd_link) {
140858ef3154SDoug Ambrisko if (syspd_pend->pd_id == pdlist->addr[i].device_id)
140958ef3154SDoug Ambrisko found = 1;
141058ef3154SDoug Ambrisko }
1411a6ba0fd6SDoug Ambrisko if (found == 0)
14120d9a4ef3SDoug Ambrisko mfi_add_sys_pd(sc, pdlist->addr[i].device_id);
14130d9a4ef3SDoug Ambrisko }
14140d9a4ef3SDoug Ambrisko /* Delete SYSPD's whose state has been changed */
1415a6ba0fd6SDoug Ambrisko TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) {
1416a6ba0fd6SDoug Ambrisko found = 0;
14170d9a4ef3SDoug Ambrisko for (i = 0; i < pdlist->count; i++) {
141808c89430SSteven Hartland if (syspd->pd_id == pdlist->addr[i].device_id) {
1419a6ba0fd6SDoug Ambrisko found = 1;
142008c89430SSteven Hartland break;
142108c89430SSteven Hartland }
14220d9a4ef3SDoug Ambrisko }
1423a6ba0fd6SDoug Ambrisko if (found == 0) {
1424a6ba0fd6SDoug Ambrisko printf("DELETE\n");
1425a6ba0fd6SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
1426c6df6f53SWarner Losh bus_topo_lock();
14270d9a4ef3SDoug Ambrisko device_delete_child(sc->mfi_dev, syspd->pd_dev);
1428c6df6f53SWarner Losh bus_topo_unlock();
1429a6ba0fd6SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
14300d9a4ef3SDoug Ambrisko }
14310d9a4ef3SDoug Ambrisko }
14320d9a4ef3SDoug Ambrisko out:
14330d9a4ef3SDoug Ambrisko if (pdlist)
14340d9a4ef3SDoug Ambrisko free(pdlist, M_MFIBUF);
14350d9a4ef3SDoug Ambrisko if (cm)
14360d9a4ef3SDoug Ambrisko mfi_release_command(cm);
14370d9a4ef3SDoug Ambrisko
14380d9a4ef3SDoug Ambrisko return;
14390d9a4ef3SDoug Ambrisko }
14402e21a3efSScott Long
14412e21a3efSScott Long static void
mfi_ldprobe(struct mfi_softc * sc)1442c0b332d1SPaul Saab mfi_ldprobe(struct mfi_softc *sc)
14432e21a3efSScott Long {
1444c0b332d1SPaul Saab struct mfi_frame_header *hdr;
1445c0b332d1SPaul Saab struct mfi_command *cm = NULL;
1446c0b332d1SPaul Saab struct mfi_ld_list *list = NULL;
14478ec5c98bSJohn Baldwin struct mfi_disk *ld;
144858ef3154SDoug Ambrisko struct mfi_disk_pending *ld_pend;
1449c0b332d1SPaul Saab int error, i;
14502e21a3efSScott Long
14518ec5c98bSJohn Baldwin sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
1452441f6d5dSScott Long mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1453441f6d5dSScott Long
1454c0b332d1SPaul Saab error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST,
1455c0b332d1SPaul Saab (void **)&list, sizeof(*list));
1456c0b332d1SPaul Saab if (error)
1457c0b332d1SPaul Saab goto out;
1458c0b332d1SPaul Saab
1459c0b332d1SPaul Saab cm->cm_flags = MFI_CMD_DATAIN;
1460c0b332d1SPaul Saab if (mfi_wait_command(sc, cm) != 0) {
1461c0b332d1SPaul Saab device_printf(sc->mfi_dev, "Failed to get device listing\n");
1462c0b332d1SPaul Saab goto out;
14632e21a3efSScott Long }
14642e21a3efSScott Long
1465c0b332d1SPaul Saab hdr = &cm->cm_frame->header;
1466c0b332d1SPaul Saab if (hdr->cmd_status != MFI_STAT_OK) {
1467c0b332d1SPaul Saab device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n",
1468c0b332d1SPaul Saab hdr->cmd_status);
1469c0b332d1SPaul Saab goto out;
1470c0b332d1SPaul Saab }
1471c0b332d1SPaul Saab
14728ec5c98bSJohn Baldwin for (i = 0; i < list->ld_count; i++) {
14738ec5c98bSJohn Baldwin TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
14748ec5c98bSJohn Baldwin if (ld->ld_id == list->ld_list[i].ld.v.target_id)
14758ec5c98bSJohn Baldwin goto skip_add;
14768ec5c98bSJohn Baldwin }
147758ef3154SDoug Ambrisko TAILQ_FOREACH(ld_pend, &sc->mfi_ld_pend_tqh, ld_link) {
147858ef3154SDoug Ambrisko if (ld_pend->ld_id == list->ld_list[i].ld.v.target_id)
147958ef3154SDoug Ambrisko goto skip_add;
148058ef3154SDoug Ambrisko }
1481441f6d5dSScott Long mfi_add_ld(sc, list->ld_list[i].ld.v.target_id);
14828ec5c98bSJohn Baldwin skip_add:;
14838ec5c98bSJohn Baldwin }
1484c0b332d1SPaul Saab out:
1485c0b332d1SPaul Saab if (list)
1486c0b332d1SPaul Saab free(list, M_MFIBUF);
1487c0b332d1SPaul Saab if (cm)
1488c0b332d1SPaul Saab mfi_release_command(cm);
1489441f6d5dSScott Long
14902e21a3efSScott Long return;
14912e21a3efSScott Long }
14922e21a3efSScott Long
14932137b017SJohn Baldwin /*
14942137b017SJohn Baldwin * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If
14952137b017SJohn Baldwin * the bits in 24-31 are all set, then it is the number of seconds since
14962137b017SJohn Baldwin * boot.
14972137b017SJohn Baldwin */
14982137b017SJohn Baldwin static const char *
format_timestamp(uint32_t timestamp)14992137b017SJohn Baldwin format_timestamp(uint32_t timestamp)
15002137b017SJohn Baldwin {
15012137b017SJohn Baldwin static char buffer[32];
15022137b017SJohn Baldwin
15032137b017SJohn Baldwin if ((timestamp & 0xff000000) == 0xff000000)
15042137b017SJohn Baldwin snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
15052137b017SJohn Baldwin 0x00ffffff);
15062137b017SJohn Baldwin else
15072137b017SJohn Baldwin snprintf(buffer, sizeof(buffer), "%us", timestamp);
15082137b017SJohn Baldwin return (buffer);
15092137b017SJohn Baldwin }
15102137b017SJohn Baldwin
15112137b017SJohn Baldwin static const char *
format_class(int8_t class)15122137b017SJohn Baldwin format_class(int8_t class)
15132137b017SJohn Baldwin {
15142137b017SJohn Baldwin static char buffer[6];
15152137b017SJohn Baldwin
15162137b017SJohn Baldwin switch (class) {
15172137b017SJohn Baldwin case MFI_EVT_CLASS_DEBUG:
15182137b017SJohn Baldwin return ("debug");
15192137b017SJohn Baldwin case MFI_EVT_CLASS_PROGRESS:
15202137b017SJohn Baldwin return ("progress");
15212137b017SJohn Baldwin case MFI_EVT_CLASS_INFO:
15222137b017SJohn Baldwin return ("info");
15232137b017SJohn Baldwin case MFI_EVT_CLASS_WARNING:
15242137b017SJohn Baldwin return ("WARN");
15252137b017SJohn Baldwin case MFI_EVT_CLASS_CRITICAL:
15262137b017SJohn Baldwin return ("CRIT");
15272137b017SJohn Baldwin case MFI_EVT_CLASS_FATAL:
15282137b017SJohn Baldwin return ("FATAL");
15292137b017SJohn Baldwin case MFI_EVT_CLASS_DEAD:
15302137b017SJohn Baldwin return ("DEAD");
15312137b017SJohn Baldwin default:
15322137b017SJohn Baldwin snprintf(buffer, sizeof(buffer), "%d", class);
15332137b017SJohn Baldwin return (buffer);
15342137b017SJohn Baldwin }
15352137b017SJohn Baldwin }
15362137b017SJohn Baldwin
1537741367d5SDoug Ambrisko static void
mfi_decode_evt(struct mfi_softc * sc,struct mfi_evt_detail * detail)1538741367d5SDoug Ambrisko mfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1539741367d5SDoug Ambrisko {
15400d9a4ef3SDoug Ambrisko struct mfi_system_pd *syspd = NULL;
15412137b017SJohn Baldwin
1542406930fbSJung-uk Kim device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq,
1543aacea6e2SEd Maste format_timestamp(detail->time), detail->evt_class.members.locale,
1544a6ba0fd6SDoug Ambrisko format_class(detail->evt_class.members.evt_class),
1545a6ba0fd6SDoug Ambrisko detail->description);
1546a6ba0fd6SDoug Ambrisko
1547a6ba0fd6SDoug Ambrisko /* Don't act on old AEN's or while shutting down */
1548a6ba0fd6SDoug Ambrisko if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching)
1549a6ba0fd6SDoug Ambrisko return;
1550a6ba0fd6SDoug Ambrisko
15510d9a4ef3SDoug Ambrisko switch (detail->arg_type) {
15520d9a4ef3SDoug Ambrisko case MR_EVT_ARGS_NONE:
15530d9a4ef3SDoug Ambrisko if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) {
15540d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "HostBus scan raised\n");
1555a6ba0fd6SDoug Ambrisko if (mfi_detect_jbod_change) {
1556a6ba0fd6SDoug Ambrisko /*
1557a6ba0fd6SDoug Ambrisko * Probe for new SYSPD's and Delete
1558a6ba0fd6SDoug Ambrisko * invalid SYSPD's
1559a6ba0fd6SDoug Ambrisko */
15600d9a4ef3SDoug Ambrisko sx_xlock(&sc->mfi_config_lock);
15610d9a4ef3SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
15620d9a4ef3SDoug Ambrisko mfi_syspdprobe(sc);
15630d9a4ef3SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
15640d9a4ef3SDoug Ambrisko sx_xunlock(&sc->mfi_config_lock);
15650d9a4ef3SDoug Ambrisko }
15660d9a4ef3SDoug Ambrisko }
15670d9a4ef3SDoug Ambrisko break;
15680d9a4ef3SDoug Ambrisko case MR_EVT_ARGS_LD_STATE:
1569a6ba0fd6SDoug Ambrisko /* During load time driver reads all the events starting
1570a6ba0fd6SDoug Ambrisko * from the one that has been logged after shutdown. Avoid
1571a6ba0fd6SDoug Ambrisko * these old events.
15720d9a4ef3SDoug Ambrisko */
15730d9a4ef3SDoug Ambrisko if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) {
15740d9a4ef3SDoug Ambrisko /* Remove the LD */
1575a6ba0fd6SDoug Ambrisko struct mfi_disk *ld;
15760d9a4ef3SDoug Ambrisko TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
1577a6ba0fd6SDoug Ambrisko if (ld->ld_id ==
1578a6ba0fd6SDoug Ambrisko detail->args.ld_state.ld.target_id)
15790d9a4ef3SDoug Ambrisko break;
15800d9a4ef3SDoug Ambrisko }
15810d9a4ef3SDoug Ambrisko /*
15820d9a4ef3SDoug Ambrisko Fix: for kernel panics when SSCD is removed
15830d9a4ef3SDoug Ambrisko KASSERT(ld != NULL, ("volume dissappeared"));
15840d9a4ef3SDoug Ambrisko */
1585a6ba0fd6SDoug Ambrisko if (ld != NULL) {
1586c6df6f53SWarner Losh bus_topo_lock();
15870d9a4ef3SDoug Ambrisko device_delete_child(sc->mfi_dev, ld->ld_dev);
1588c6df6f53SWarner Losh bus_topo_unlock();
15890d9a4ef3SDoug Ambrisko }
15900d9a4ef3SDoug Ambrisko }
15910d9a4ef3SDoug Ambrisko break;
15920d9a4ef3SDoug Ambrisko case MR_EVT_ARGS_PD:
15930d9a4ef3SDoug Ambrisko if (detail->code == MR_EVT_PD_REMOVED) {
1594a6ba0fd6SDoug Ambrisko if (mfi_detect_jbod_change) {
1595a6ba0fd6SDoug Ambrisko /*
1596a6ba0fd6SDoug Ambrisko * If the removed device is a SYSPD then
1597a6ba0fd6SDoug Ambrisko * delete it
1598a6ba0fd6SDoug Ambrisko */
1599a6ba0fd6SDoug Ambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,
1600a6ba0fd6SDoug Ambrisko pd_link) {
1601a6ba0fd6SDoug Ambrisko if (syspd->pd_id ==
1602a6ba0fd6SDoug Ambrisko detail->args.pd.device_id) {
1603c6df6f53SWarner Losh bus_topo_lock();
1604a6ba0fd6SDoug Ambrisko device_delete_child(
1605a6ba0fd6SDoug Ambrisko sc->mfi_dev,
1606a6ba0fd6SDoug Ambrisko syspd->pd_dev);
1607c6df6f53SWarner Losh bus_topo_unlock();
16080d9a4ef3SDoug Ambrisko break;
16090d9a4ef3SDoug Ambrisko }
16100d9a4ef3SDoug Ambrisko }
16110d9a4ef3SDoug Ambrisko }
16120d9a4ef3SDoug Ambrisko }
16130d9a4ef3SDoug Ambrisko if (detail->code == MR_EVT_PD_INSERTED) {
1614a6ba0fd6SDoug Ambrisko if (mfi_detect_jbod_change) {
16150d9a4ef3SDoug Ambrisko /* Probe for new SYSPD's */
16160d9a4ef3SDoug Ambrisko sx_xlock(&sc->mfi_config_lock);
16170d9a4ef3SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
16180d9a4ef3SDoug Ambrisko mfi_syspdprobe(sc);
16190d9a4ef3SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
16200d9a4ef3SDoug Ambrisko sx_xunlock(&sc->mfi_config_lock);
16210d9a4ef3SDoug Ambrisko }
16220d9a4ef3SDoug Ambrisko }
162359ddd3e9SDoug Ambrisko if (sc->mfi_cam_rescan_cb != NULL &&
162459ddd3e9SDoug Ambrisko (detail->code == MR_EVT_PD_INSERTED ||
162559ddd3e9SDoug Ambrisko detail->code == MR_EVT_PD_REMOVED)) {
162659ddd3e9SDoug Ambrisko sc->mfi_cam_rescan_cb(sc, detail->args.pd.device_id);
162759ddd3e9SDoug Ambrisko }
16280d9a4ef3SDoug Ambrisko break;
16290d9a4ef3SDoug Ambrisko }
1630a6ba0fd6SDoug Ambrisko }
16312137b017SJohn Baldwin
1632a6ba0fd6SDoug Ambrisko static void
mfi_queue_evt(struct mfi_softc * sc,struct mfi_evt_detail * detail)1633a6ba0fd6SDoug Ambrisko mfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
1634a6ba0fd6SDoug Ambrisko {
1635a6ba0fd6SDoug Ambrisko struct mfi_evt_queue_elm *elm;
1636a6ba0fd6SDoug Ambrisko
1637a6ba0fd6SDoug Ambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1638a6ba0fd6SDoug Ambrisko elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO);
1639a6ba0fd6SDoug Ambrisko if (elm == NULL)
1640a6ba0fd6SDoug Ambrisko return;
1641a6ba0fd6SDoug Ambrisko memcpy(&elm->detail, detail, sizeof(*detail));
1642a6ba0fd6SDoug Ambrisko TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link);
1643a6ba0fd6SDoug Ambrisko taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task);
1644a6ba0fd6SDoug Ambrisko }
1645a6ba0fd6SDoug Ambrisko
1646a6ba0fd6SDoug Ambrisko static void
mfi_handle_evt(void * context,int pending)1647a6ba0fd6SDoug Ambrisko mfi_handle_evt(void *context, int pending)
1648a6ba0fd6SDoug Ambrisko {
1649a6ba0fd6SDoug Ambrisko TAILQ_HEAD(,mfi_evt_queue_elm) queue;
1650a6ba0fd6SDoug Ambrisko struct mfi_softc *sc;
1651a6ba0fd6SDoug Ambrisko struct mfi_evt_queue_elm *elm;
1652a6ba0fd6SDoug Ambrisko
1653a6ba0fd6SDoug Ambrisko sc = context;
1654a6ba0fd6SDoug Ambrisko TAILQ_INIT(&queue);
1655a6ba0fd6SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
1656a6ba0fd6SDoug Ambrisko TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link);
1657a6ba0fd6SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
1658a6ba0fd6SDoug Ambrisko while ((elm = TAILQ_FIRST(&queue)) != NULL) {
1659a6ba0fd6SDoug Ambrisko TAILQ_REMOVE(&queue, elm, link);
1660a6ba0fd6SDoug Ambrisko mfi_decode_evt(sc, &elm->detail);
1661a6ba0fd6SDoug Ambrisko free(elm, M_MFIBUF);
1662a6ba0fd6SDoug Ambrisko }
1663741367d5SDoug Ambrisko }
1664741367d5SDoug Ambrisko
1665741367d5SDoug Ambrisko static int
mfi_aen_register(struct mfi_softc * sc,int seq,int locale)1666741367d5SDoug Ambrisko mfi_aen_register(struct mfi_softc *sc, int seq, int locale)
1667741367d5SDoug Ambrisko {
1668741367d5SDoug Ambrisko struct mfi_command *cm;
1669741367d5SDoug Ambrisko struct mfi_dcmd_frame *dcmd;
1670741367d5SDoug Ambrisko union mfi_evt current_aen, prior_aen;
1671fb595e7aSPaul Saab struct mfi_evt_detail *ed = NULL;
1672441f6d5dSScott Long int error = 0;
1673741367d5SDoug Ambrisko
167408c89430SSteven Hartland mtx_assert(&sc->mfi_io_lock, MA_OWNED);
167508c89430SSteven Hartland
1676741367d5SDoug Ambrisko current_aen.word = locale;
1677741367d5SDoug Ambrisko if (sc->mfi_aen_cm != NULL) {
1678741367d5SDoug Ambrisko prior_aen.word =
1679741367d5SDoug Ambrisko ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1];
1680aacea6e2SEd Maste if (prior_aen.members.evt_class <= current_aen.members.evt_class &&
1681741367d5SDoug Ambrisko !((prior_aen.members.locale & current_aen.members.locale)
1682741367d5SDoug Ambrisko ^current_aen.members.locale)) {
1683741367d5SDoug Ambrisko return (0);
1684741367d5SDoug Ambrisko } else {
1685741367d5SDoug Ambrisko prior_aen.members.locale |= current_aen.members.locale;
1686aacea6e2SEd Maste if (prior_aen.members.evt_class
1687aacea6e2SEd Maste < current_aen.members.evt_class)
1688aacea6e2SEd Maste current_aen.members.evt_class =
1689aacea6e2SEd Maste prior_aen.members.evt_class;
169058ef3154SDoug Ambrisko mfi_abort(sc, &sc->mfi_aen_cm);
1691741367d5SDoug Ambrisko }
1692741367d5SDoug Ambrisko }
1693741367d5SDoug Ambrisko
1694fb595e7aSPaul Saab error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
1695fb595e7aSPaul Saab (void **)&ed, sizeof(*ed));
169608c89430SSteven Hartland if (error)
1697441f6d5dSScott Long goto out;
1698741367d5SDoug Ambrisko
1699741367d5SDoug Ambrisko dcmd = &cm->cm_frame->dcmd;
1700741367d5SDoug Ambrisko ((uint32_t *)&dcmd->mbox)[0] = seq;
1701741367d5SDoug Ambrisko ((uint32_t *)&dcmd->mbox)[1] = locale;
1702741367d5SDoug Ambrisko cm->cm_flags = MFI_CMD_DATAIN;
1703741367d5SDoug Ambrisko cm->cm_complete = mfi_aen_complete;
1704741367d5SDoug Ambrisko
17050d9a4ef3SDoug Ambrisko sc->last_seq_num = seq;
1706741367d5SDoug Ambrisko sc->mfi_aen_cm = cm;
1707741367d5SDoug Ambrisko
1708741367d5SDoug Ambrisko mfi_enqueue_ready(cm);
1709741367d5SDoug Ambrisko mfi_startio(sc);
1710741367d5SDoug Ambrisko
1711441f6d5dSScott Long out:
1712441f6d5dSScott Long return (error);
1713741367d5SDoug Ambrisko }
1714741367d5SDoug Ambrisko
1715741367d5SDoug Ambrisko static void
mfi_aen_complete(struct mfi_command * cm)1716741367d5SDoug Ambrisko mfi_aen_complete(struct mfi_command *cm)
1717741367d5SDoug Ambrisko {
1718741367d5SDoug Ambrisko struct mfi_frame_header *hdr;
1719741367d5SDoug Ambrisko struct mfi_softc *sc;
1720741367d5SDoug Ambrisko struct mfi_evt_detail *detail;
1721441f6d5dSScott Long struct mfi_aen *mfi_aen_entry, *tmp;
1722741367d5SDoug Ambrisko int seq = 0, aborted = 0;
1723741367d5SDoug Ambrisko
1724741367d5SDoug Ambrisko sc = cm->cm_sc;
17250d9a4ef3SDoug Ambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED);
17260d9a4ef3SDoug Ambrisko
1727741367d5SDoug Ambrisko if (sc->mfi_aen_cm == NULL)
1728741367d5SDoug Ambrisko return;
1729741367d5SDoug Ambrisko
173008c89430SSteven Hartland hdr = &cm->cm_frame->header;
173108c89430SSteven Hartland
1732ddbffe7fSDoug Ambrisko if (sc->cm_aen_abort ||
1733c2e3261aSJohn Baldwin hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
1734ddbffe7fSDoug Ambrisko sc->cm_aen_abort = 0;
1735741367d5SDoug Ambrisko aborted = 1;
1736741367d5SDoug Ambrisko } else {
1737741367d5SDoug Ambrisko sc->mfi_aen_triggered = 1;
1738441f6d5dSScott Long if (sc->mfi_poll_waiting) {
1739441f6d5dSScott Long sc->mfi_poll_waiting = 0;
1740741367d5SDoug Ambrisko selwakeup(&sc->mfi_select);
1741441f6d5dSScott Long }
1742741367d5SDoug Ambrisko detail = cm->cm_data;
1743a6ba0fd6SDoug Ambrisko mfi_queue_evt(sc, detail);
1744741367d5SDoug Ambrisko seq = detail->seq + 1;
1745a6ba0fd6SDoug Ambrisko TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link,
1746a6ba0fd6SDoug Ambrisko tmp) {
1747741367d5SDoug Ambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
1748741367d5SDoug Ambrisko aen_link);
1749441f6d5dSScott Long PROC_LOCK(mfi_aen_entry->p);
17508451d0ddSKip Macy kern_psignal(mfi_aen_entry->p, SIGIO);
1751441f6d5dSScott Long PROC_UNLOCK(mfi_aen_entry->p);
1752741367d5SDoug Ambrisko free(mfi_aen_entry, M_MFIBUF);
1753741367d5SDoug Ambrisko }
1754741367d5SDoug Ambrisko }
1755741367d5SDoug Ambrisko
1756741367d5SDoug Ambrisko free(cm->cm_data, M_MFIBUF);
1757741367d5SDoug Ambrisko wakeup(&sc->mfi_aen_cm);
175808c89430SSteven Hartland sc->mfi_aen_cm = NULL;
1759741367d5SDoug Ambrisko mfi_release_command(cm);
1760741367d5SDoug Ambrisko
1761741367d5SDoug Ambrisko /* set it up again so the driver can catch more events */
176208c89430SSteven Hartland if (!aborted)
1763741367d5SDoug Ambrisko mfi_aen_setup(sc, seq);
1764741367d5SDoug Ambrisko }
1765741367d5SDoug Ambrisko
1766c1ed06a8SJohn Baldwin #define MAX_EVENTS 15
1767c1ed06a8SJohn Baldwin
1768741367d5SDoug Ambrisko static int
mfi_parse_entries(struct mfi_softc * sc,int start_seq,int stop_seq)1769c1ed06a8SJohn Baldwin mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
1770741367d5SDoug Ambrisko {
1771741367d5SDoug Ambrisko struct mfi_command *cm;
1772741367d5SDoug Ambrisko struct mfi_dcmd_frame *dcmd;
177347b470b9SDoug Ambrisko struct mfi_evt_list *el;
1774c1ed06a8SJohn Baldwin union mfi_evt class_locale;
1775c1ed06a8SJohn Baldwin int error, i, seq, size;
1776741367d5SDoug Ambrisko
177708c89430SSteven Hartland mtx_assert(&sc->mfi_io_lock, MA_OWNED);
177808c89430SSteven Hartland
1779c1ed06a8SJohn Baldwin class_locale.members.reserved = 0;
1780c1ed06a8SJohn Baldwin class_locale.members.locale = mfi_event_locale;
1781aacea6e2SEd Maste class_locale.members.evt_class = mfi_event_class;
1782741367d5SDoug Ambrisko
178347b470b9SDoug Ambrisko size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail)
178447b470b9SDoug Ambrisko * (MAX_EVENTS - 1);
178547b470b9SDoug Ambrisko el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO);
1786c1ed06a8SJohn Baldwin if (el == NULL)
1787741367d5SDoug Ambrisko return (ENOMEM);
1788c1ed06a8SJohn Baldwin
1789c1ed06a8SJohn Baldwin for (seq = start_seq;;) {
1790c1ed06a8SJohn Baldwin if ((cm = mfi_dequeue_free(sc)) == NULL) {
1791c1ed06a8SJohn Baldwin free(el, M_MFIBUF);
1792c1ed06a8SJohn Baldwin return (EBUSY);
1793741367d5SDoug Ambrisko }
1794741367d5SDoug Ambrisko
1795741367d5SDoug Ambrisko dcmd = &cm->cm_frame->dcmd;
1796741367d5SDoug Ambrisko bzero(dcmd->mbox, MFI_MBOX_SIZE);
1797741367d5SDoug Ambrisko dcmd->header.cmd = MFI_CMD_DCMD;
1798741367d5SDoug Ambrisko dcmd->header.timeout = 0;
179947b470b9SDoug Ambrisko dcmd->header.data_len = size;
1800741367d5SDoug Ambrisko dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET;
1801741367d5SDoug Ambrisko ((uint32_t *)&dcmd->mbox)[0] = seq;
1802c1ed06a8SJohn Baldwin ((uint32_t *)&dcmd->mbox)[1] = class_locale.word;
1803741367d5SDoug Ambrisko cm->cm_sg = &dcmd->sgl;
1804741367d5SDoug Ambrisko cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
1805741367d5SDoug Ambrisko cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
180647b470b9SDoug Ambrisko cm->cm_data = el;
180747b470b9SDoug Ambrisko cm->cm_len = size;
1808741367d5SDoug Ambrisko
1809741367d5SDoug Ambrisko if ((error = mfi_mapcmd(sc, cm)) != 0) {
1810c1ed06a8SJohn Baldwin device_printf(sc->mfi_dev,
1811c1ed06a8SJohn Baldwin "Failed to get controller entries\n");
1812741367d5SDoug Ambrisko mfi_release_command(cm);
1813c1ed06a8SJohn Baldwin break;
1814741367d5SDoug Ambrisko }
1815741367d5SDoug Ambrisko
1816741367d5SDoug Ambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1817741367d5SDoug Ambrisko BUS_DMASYNC_POSTREAD);
1818741367d5SDoug Ambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
1819741367d5SDoug Ambrisko
1820c1ed06a8SJohn Baldwin if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) {
1821c1ed06a8SJohn Baldwin mfi_release_command(cm);
1822c1ed06a8SJohn Baldwin break;
1823c1ed06a8SJohn Baldwin }
1824c1ed06a8SJohn Baldwin if (dcmd->header.cmd_status != MFI_STAT_OK) {
1825c1ed06a8SJohn Baldwin device_printf(sc->mfi_dev,
1826c1ed06a8SJohn Baldwin "Error %d fetching controller entries\n",
1827c1ed06a8SJohn Baldwin dcmd->header.cmd_status);
1828c1ed06a8SJohn Baldwin mfi_release_command(cm);
182908c89430SSteven Hartland error = EIO;
1830c1ed06a8SJohn Baldwin break;
1831c1ed06a8SJohn Baldwin }
1832c1ed06a8SJohn Baldwin mfi_release_command(cm);
1833c1ed06a8SJohn Baldwin
183447b470b9SDoug Ambrisko for (i = 0; i < el->count; i++) {
1835c1ed06a8SJohn Baldwin /*
1836c1ed06a8SJohn Baldwin * If this event is newer than 'stop_seq' then
1837c1ed06a8SJohn Baldwin * break out of the loop. Note that the log
1838c1ed06a8SJohn Baldwin * is a circular buffer so we have to handle
1839c1ed06a8SJohn Baldwin * the case that our stop point is earlier in
1840c1ed06a8SJohn Baldwin * the buffer than our start point.
1841c1ed06a8SJohn Baldwin */
1842c1ed06a8SJohn Baldwin if (el->event[i].seq >= stop_seq) {
1843c1ed06a8SJohn Baldwin if (start_seq <= stop_seq)
1844c1ed06a8SJohn Baldwin break;
1845c1ed06a8SJohn Baldwin else if (el->event[i].seq < start_seq)
1846c1ed06a8SJohn Baldwin break;
1847c1ed06a8SJohn Baldwin }
1848a6ba0fd6SDoug Ambrisko mfi_queue_evt(sc, &el->event[i]);
1849a1adc445SDoug Ambrisko }
1850c1ed06a8SJohn Baldwin seq = el->event[el->count - 1].seq + 1;
185147b470b9SDoug Ambrisko }
1852741367d5SDoug Ambrisko
1853c1ed06a8SJohn Baldwin free(el, M_MFIBUF);
185408c89430SSteven Hartland return (error);
1855741367d5SDoug Ambrisko }
1856741367d5SDoug Ambrisko
18572e21a3efSScott Long static int
mfi_add_ld(struct mfi_softc * sc,int id)1858c0b332d1SPaul Saab mfi_add_ld(struct mfi_softc *sc, int id)
18592e21a3efSScott Long {
18602e21a3efSScott Long struct mfi_command *cm;
1861c0b332d1SPaul Saab struct mfi_dcmd_frame *dcmd = NULL;
1862c0b332d1SPaul Saab struct mfi_ld_info *ld_info = NULL;
186358ef3154SDoug Ambrisko struct mfi_disk_pending *ld_pend;
1864c0b332d1SPaul Saab int error;
18652e21a3efSScott Long
1866c0b332d1SPaul Saab mtx_assert(&sc->mfi_io_lock, MA_OWNED);
1867c0b332d1SPaul Saab
186858ef3154SDoug Ambrisko ld_pend = malloc(sizeof(*ld_pend), M_MFIBUF, M_NOWAIT | M_ZERO);
186958ef3154SDoug Ambrisko if (ld_pend != NULL) {
187058ef3154SDoug Ambrisko ld_pend->ld_id = id;
187158ef3154SDoug Ambrisko TAILQ_INSERT_TAIL(&sc->mfi_ld_pend_tqh, ld_pend, ld_link);
187258ef3154SDoug Ambrisko }
187358ef3154SDoug Ambrisko
1874c0b332d1SPaul Saab error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO,
1875c0b332d1SPaul Saab (void **)&ld_info, sizeof(*ld_info));
1876c0b332d1SPaul Saab if (error) {
1877c0b332d1SPaul Saab device_printf(sc->mfi_dev,
1878c0b332d1SPaul Saab "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error);
1879c0b332d1SPaul Saab if (ld_info)
1880c0b332d1SPaul Saab free(ld_info, M_MFIBUF);
1881c0b332d1SPaul Saab return (error);
1882d21c5e5eSScott Long }
1883c0b332d1SPaul Saab cm->cm_flags = MFI_CMD_DATAIN;
1884c0b332d1SPaul Saab dcmd = &cm->cm_frame->dcmd;
1885c0b332d1SPaul Saab dcmd->mbox[0] = id;
188678997d85SDoug Ambrisko if (mfi_wait_command(sc, cm) != 0) {
188778997d85SDoug Ambrisko device_printf(sc->mfi_dev,
188878997d85SDoug Ambrisko "Failed to get logical drive: %d\n", id);
188978997d85SDoug Ambrisko free(ld_info, M_MFIBUF);
189078997d85SDoug Ambrisko return (0);
189178997d85SDoug Ambrisko }
18920d9a4ef3SDoug Ambrisko if (ld_info->ld_config.params.isSSCD != 1)
189378997d85SDoug Ambrisko mfi_add_ld_complete(cm);
1894a6ba0fd6SDoug Ambrisko else {
18950d9a4ef3SDoug Ambrisko mfi_release_command(cm);
18960d9a4ef3SDoug Ambrisko if (ld_info) /* SSCD drives ld_info free here */
18970d9a4ef3SDoug Ambrisko free(ld_info, M_MFIBUF);
18980d9a4ef3SDoug Ambrisko }
18992e21a3efSScott Long return (0);
19002e21a3efSScott Long }
19012e21a3efSScott Long
19022e21a3efSScott Long static void
mfi_add_ld_complete(struct mfi_command * cm)1903c0b332d1SPaul Saab mfi_add_ld_complete(struct mfi_command *cm)
19042e21a3efSScott Long {
19052e21a3efSScott Long struct mfi_frame_header *hdr;
1906c0b332d1SPaul Saab struct mfi_ld_info *ld_info;
19072e21a3efSScott Long struct mfi_softc *sc;
19082e21a3efSScott Long device_t child;
19092e21a3efSScott Long
1910c0b332d1SPaul Saab sc = cm->cm_sc;
1911c0b332d1SPaul Saab hdr = &cm->cm_frame->header;
1912c0b332d1SPaul Saab ld_info = cm->cm_private;
1913c0b332d1SPaul Saab
191458ef3154SDoug Ambrisko if (sc->cm_map_abort || hdr->cmd_status != MFI_STAT_OK) {
1915c0b332d1SPaul Saab free(ld_info, M_MFIBUF);
191658ef3154SDoug Ambrisko wakeup(&sc->mfi_map_sync_cm);
1917c0b332d1SPaul Saab mfi_release_command(cm);
1918c0b332d1SPaul Saab return;
191920df0de4SScott Long }
192058ef3154SDoug Ambrisko wakeup(&sc->mfi_map_sync_cm);
1921c0b332d1SPaul Saab mfi_release_command(cm);
192220df0de4SScott Long
192335ef86f2SScott Long mtx_unlock(&sc->mfi_io_lock);
1924c6df6f53SWarner Losh bus_topo_lock();
1925*b670c9baSAhmad Khalifa if ((child = device_add_child(sc->mfi_dev, "mfid",
1926*b670c9baSAhmad Khalifa DEVICE_UNIT_ANY)) == NULL) {
19272e21a3efSScott Long device_printf(sc->mfi_dev, "Failed to add logical disk\n");
1928c0b332d1SPaul Saab free(ld_info, M_MFIBUF);
1929c6df6f53SWarner Losh bus_topo_unlock();
193035ef86f2SScott Long mtx_lock(&sc->mfi_io_lock);
1931c0b332d1SPaul Saab return;
19322e21a3efSScott Long }
19332e21a3efSScott Long
1934ddfae47bSScott Long device_set_ivars(child, ld_info);
19352e21a3efSScott Long device_set_desc(child, "MFI Logical Disk");
193618250ec6SJohn Baldwin bus_attach_children(sc->mfi_dev);
1937c6df6f53SWarner Losh bus_topo_unlock();
19382e21a3efSScott Long mtx_lock(&sc->mfi_io_lock);
19392e21a3efSScott Long }
19406d678f8eSScott Long
mfi_add_sys_pd(struct mfi_softc * sc,int id)19410d9a4ef3SDoug Ambrisko static int mfi_add_sys_pd(struct mfi_softc *sc, int id)
19420d9a4ef3SDoug Ambrisko {
19430d9a4ef3SDoug Ambrisko struct mfi_command *cm;
19440d9a4ef3SDoug Ambrisko struct mfi_dcmd_frame *dcmd = NULL;
19450d9a4ef3SDoug Ambrisko struct mfi_pd_info *pd_info = NULL;
194658ef3154SDoug Ambrisko struct mfi_system_pending *syspd_pend;
19470d9a4ef3SDoug Ambrisko int error;
19480d9a4ef3SDoug Ambrisko
19490d9a4ef3SDoug Ambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED);
19500d9a4ef3SDoug Ambrisko
195158ef3154SDoug Ambrisko syspd_pend = malloc(sizeof(*syspd_pend), M_MFIBUF, M_NOWAIT | M_ZERO);
195258ef3154SDoug Ambrisko if (syspd_pend != NULL) {
195358ef3154SDoug Ambrisko syspd_pend->pd_id = id;
195458ef3154SDoug Ambrisko TAILQ_INSERT_TAIL(&sc->mfi_syspd_pend_tqh, syspd_pend, pd_link);
195558ef3154SDoug Ambrisko }
195658ef3154SDoug Ambrisko
19570d9a4ef3SDoug Ambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO,
19580d9a4ef3SDoug Ambrisko (void **)&pd_info, sizeof(*pd_info));
19590d9a4ef3SDoug Ambrisko if (error) {
19600d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev,
1961a6ba0fd6SDoug Ambrisko "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n",
1962a6ba0fd6SDoug Ambrisko error);
19630d9a4ef3SDoug Ambrisko if (pd_info)
19640d9a4ef3SDoug Ambrisko free(pd_info, M_MFIBUF);
19650d9a4ef3SDoug Ambrisko return (error);
19660d9a4ef3SDoug Ambrisko }
19670d9a4ef3SDoug Ambrisko cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
19680d9a4ef3SDoug Ambrisko dcmd = &cm->cm_frame->dcmd;
19690d9a4ef3SDoug Ambrisko dcmd->mbox[0]=id;
19700d9a4ef3SDoug Ambrisko dcmd->header.scsi_status = 0;
19710d9a4ef3SDoug Ambrisko dcmd->header.pad0 = 0;
197208c89430SSteven Hartland if ((error = mfi_mapcmd(sc, cm)) != 0) {
19730d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev,
19740d9a4ef3SDoug Ambrisko "Failed to get physical drive info %d\n", id);
19750d9a4ef3SDoug Ambrisko free(pd_info, M_MFIBUF);
197608c89430SSteven Hartland mfi_release_command(cm);
197708c89430SSteven Hartland return (error);
19780d9a4ef3SDoug Ambrisko }
1979a6ba0fd6SDoug Ambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
1980a6ba0fd6SDoug Ambrisko BUS_DMASYNC_POSTREAD);
19810d9a4ef3SDoug Ambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
19820d9a4ef3SDoug Ambrisko mfi_add_sys_pd_complete(cm);
19830d9a4ef3SDoug Ambrisko return (0);
19840d9a4ef3SDoug Ambrisko }
19850d9a4ef3SDoug Ambrisko
19860d9a4ef3SDoug Ambrisko static void
mfi_add_sys_pd_complete(struct mfi_command * cm)19870d9a4ef3SDoug Ambrisko mfi_add_sys_pd_complete(struct mfi_command *cm)
19880d9a4ef3SDoug Ambrisko {
19890d9a4ef3SDoug Ambrisko struct mfi_frame_header *hdr;
19900d9a4ef3SDoug Ambrisko struct mfi_pd_info *pd_info;
19910d9a4ef3SDoug Ambrisko struct mfi_softc *sc;
19920d9a4ef3SDoug Ambrisko device_t child;
19930d9a4ef3SDoug Ambrisko
19940d9a4ef3SDoug Ambrisko sc = cm->cm_sc;
19950d9a4ef3SDoug Ambrisko hdr = &cm->cm_frame->header;
19960d9a4ef3SDoug Ambrisko pd_info = cm->cm_private;
19970d9a4ef3SDoug Ambrisko
19980d9a4ef3SDoug Ambrisko if (hdr->cmd_status != MFI_STAT_OK) {
19990d9a4ef3SDoug Ambrisko free(pd_info, M_MFIBUF);
20000d9a4ef3SDoug Ambrisko mfi_release_command(cm);
20010d9a4ef3SDoug Ambrisko return;
20020d9a4ef3SDoug Ambrisko }
20030d9a4ef3SDoug Ambrisko if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) {
20040d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n",
20050d9a4ef3SDoug Ambrisko pd_info->ref.v.device_id);
20060d9a4ef3SDoug Ambrisko free(pd_info, M_MFIBUF);
20070d9a4ef3SDoug Ambrisko mfi_release_command(cm);
20080d9a4ef3SDoug Ambrisko return;
20090d9a4ef3SDoug Ambrisko }
20100d9a4ef3SDoug Ambrisko mfi_release_command(cm);
20110d9a4ef3SDoug Ambrisko
20120d9a4ef3SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
2013c6df6f53SWarner Losh bus_topo_lock();
2014*b670c9baSAhmad Khalifa if ((child = device_add_child(sc->mfi_dev, "mfisyspd",
2015*b670c9baSAhmad Khalifa DEVICE_UNIT_ANY)) == NULL) {
20160d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "Failed to add system pd\n");
20170d9a4ef3SDoug Ambrisko free(pd_info, M_MFIBUF);
2018c6df6f53SWarner Losh bus_topo_unlock();
20190d9a4ef3SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
20200d9a4ef3SDoug Ambrisko return;
20210d9a4ef3SDoug Ambrisko }
20220d9a4ef3SDoug Ambrisko
20230d9a4ef3SDoug Ambrisko device_set_ivars(child, pd_info);
20240d9a4ef3SDoug Ambrisko device_set_desc(child, "MFI System PD");
202518250ec6SJohn Baldwin bus_attach_children(sc->mfi_dev);
2026c6df6f53SWarner Losh bus_topo_unlock();
20270d9a4ef3SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
20280d9a4ef3SDoug Ambrisko }
202952d5baa2SDoug Ambrisko
20302e21a3efSScott Long static struct mfi_command *
mfi_bio_command(struct mfi_softc * sc)20312e21a3efSScott Long mfi_bio_command(struct mfi_softc *sc)
20322e21a3efSScott Long {
20332e21a3efSScott Long struct bio *bio;
20340d9a4ef3SDoug Ambrisko struct mfi_command *cm = NULL;
20350d9a4ef3SDoug Ambrisko
20360d9a4ef3SDoug Ambrisko /*reserving two commands to avoid starvation for IOCTL*/
20370d9a4ef3SDoug Ambrisko if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) {
20380d9a4ef3SDoug Ambrisko return (NULL);
20390d9a4ef3SDoug Ambrisko }
20400d9a4ef3SDoug Ambrisko if ((bio = mfi_dequeue_bio(sc)) == NULL) {
20410d9a4ef3SDoug Ambrisko return (NULL);
20420d9a4ef3SDoug Ambrisko }
20430d9a4ef3SDoug Ambrisko if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) {
20440d9a4ef3SDoug Ambrisko cm = mfi_build_ldio(sc, bio);
20450d9a4ef3SDoug Ambrisko } else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) {
20460d9a4ef3SDoug Ambrisko cm = mfi_build_syspdio(sc, bio);
20470d9a4ef3SDoug Ambrisko }
20480d9a4ef3SDoug Ambrisko if (!cm)
20490d9a4ef3SDoug Ambrisko mfi_enqueue_bio(sc, bio);
20500d9a4ef3SDoug Ambrisko return cm;
20510d9a4ef3SDoug Ambrisko }
2052808df726SXin LI
205358ef3154SDoug Ambrisko /*
205458ef3154SDoug Ambrisko * mostly copied from cam/scsi/scsi_all.c:scsi_read_write
205558ef3154SDoug Ambrisko */
205658ef3154SDoug Ambrisko
205758ef3154SDoug Ambrisko int
mfi_build_cdb(int readop,uint8_t byte2,u_int64_t lba,u_int32_t block_count,uint8_t * cdb)205858ef3154SDoug Ambrisko mfi_build_cdb(int readop, uint8_t byte2, u_int64_t lba, u_int32_t block_count, uint8_t *cdb)
2059808df726SXin LI {
2060808df726SXin LI int cdb_len;
2061808df726SXin LI
2062808df726SXin LI if (((lba & 0x1fffff) == lba)
2063808df726SXin LI && ((block_count & 0xff) == block_count)
2064808df726SXin LI && (byte2 == 0)) {
2065808df726SXin LI /* We can fit in a 6 byte cdb */
2066808df726SXin LI struct scsi_rw_6 *scsi_cmd;
2067808df726SXin LI
206858ef3154SDoug Ambrisko scsi_cmd = (struct scsi_rw_6 *)cdb;
2069808df726SXin LI scsi_cmd->opcode = readop ? READ_6 : WRITE_6;
2070808df726SXin LI scsi_ulto3b(lba, scsi_cmd->addr);
2071808df726SXin LI scsi_cmd->length = block_count & 0xff;
2072808df726SXin LI scsi_cmd->control = 0;
2073808df726SXin LI cdb_len = sizeof(*scsi_cmd);
2074808df726SXin LI } else if (((block_count & 0xffff) == block_count) && ((lba & 0xffffffff) == lba)) {
2075808df726SXin LI /* Need a 10 byte CDB */
2076808df726SXin LI struct scsi_rw_10 *scsi_cmd;
2077808df726SXin LI
207858ef3154SDoug Ambrisko scsi_cmd = (struct scsi_rw_10 *)cdb;
2079808df726SXin LI scsi_cmd->opcode = readop ? READ_10 : WRITE_10;
2080808df726SXin LI scsi_cmd->byte2 = byte2;
2081808df726SXin LI scsi_ulto4b(lba, scsi_cmd->addr);
2082808df726SXin LI scsi_cmd->reserved = 0;
2083808df726SXin LI scsi_ulto2b(block_count, scsi_cmd->length);
2084808df726SXin LI scsi_cmd->control = 0;
2085808df726SXin LI cdb_len = sizeof(*scsi_cmd);
2086808df726SXin LI } else if (((block_count & 0xffffffff) == block_count) &&
2087808df726SXin LI ((lba & 0xffffffff) == lba)) {
2088808df726SXin LI /* Block count is too big for 10 byte CDB use a 12 byte CDB */
2089808df726SXin LI struct scsi_rw_12 *scsi_cmd;
2090808df726SXin LI
209158ef3154SDoug Ambrisko scsi_cmd = (struct scsi_rw_12 *)cdb;
2092808df726SXin LI scsi_cmd->opcode = readop ? READ_12 : WRITE_12;
2093808df726SXin LI scsi_cmd->byte2 = byte2;
2094808df726SXin LI scsi_ulto4b(lba, scsi_cmd->addr);
2095808df726SXin LI scsi_cmd->reserved = 0;
2096808df726SXin LI scsi_ulto4b(block_count, scsi_cmd->length);
2097808df726SXin LI scsi_cmd->control = 0;
2098808df726SXin LI cdb_len = sizeof(*scsi_cmd);
2099808df726SXin LI } else {
2100808df726SXin LI /*
2101808df726SXin LI * 16 byte CDB. We'll only get here if the LBA is larger
2102808df726SXin LI * than 2^32
2103808df726SXin LI */
2104808df726SXin LI struct scsi_rw_16 *scsi_cmd;
2105808df726SXin LI
210658ef3154SDoug Ambrisko scsi_cmd = (struct scsi_rw_16 *)cdb;
2107808df726SXin LI scsi_cmd->opcode = readop ? READ_16 : WRITE_16;
2108808df726SXin LI scsi_cmd->byte2 = byte2;
2109808df726SXin LI scsi_u64to8b(lba, scsi_cmd->addr);
2110808df726SXin LI scsi_cmd->reserved = 0;
2111808df726SXin LI scsi_ulto4b(block_count, scsi_cmd->length);
2112808df726SXin LI scsi_cmd->control = 0;
2113808df726SXin LI cdb_len = sizeof(*scsi_cmd);
2114808df726SXin LI }
2115808df726SXin LI
2116808df726SXin LI return cdb_len;
2117808df726SXin LI }
2118808df726SXin LI
2119c33ce503SKonstantin Belousov extern char *unmapped_buf;
2120c33ce503SKonstantin Belousov
21210d9a4ef3SDoug Ambrisko static struct mfi_command *
mfi_build_syspdio(struct mfi_softc * sc,struct bio * bio)21220d9a4ef3SDoug Ambrisko mfi_build_syspdio(struct mfi_softc *sc, struct bio *bio)
21230d9a4ef3SDoug Ambrisko {
21240d9a4ef3SDoug Ambrisko struct mfi_command *cm;
21250d9a4ef3SDoug Ambrisko struct mfi_pass_frame *pass;
212658ef3154SDoug Ambrisko uint32_t context = 0;
212758ef3154SDoug Ambrisko int flags = 0, blkcount = 0, readop;
2128808df726SXin LI uint8_t cdb_len;
21292e21a3efSScott Long
213008c89430SSteven Hartland mtx_assert(&sc->mfi_io_lock, MA_OWNED);
213108c89430SSteven Hartland
21322e21a3efSScott Long if ((cm = mfi_dequeue_free(sc)) == NULL)
21332e21a3efSScott Long return (NULL);
21342e21a3efSScott Long
21350d9a4ef3SDoug Ambrisko /* Zero out the MFI frame */
21360d9a4ef3SDoug Ambrisko context = cm->cm_frame->header.context;
21370d9a4ef3SDoug Ambrisko bzero(cm->cm_frame, sizeof(union mfi_frame));
21380d9a4ef3SDoug Ambrisko cm->cm_frame->header.context = context;
21390d9a4ef3SDoug Ambrisko pass = &cm->cm_frame->pass;
21400d9a4ef3SDoug Ambrisko bzero(pass->cdb, 16);
21410d9a4ef3SDoug Ambrisko pass->header.cmd = MFI_CMD_PD_SCSI_IO;
2142225e4b42SWarner Losh switch (bio->bio_cmd) {
21430d9a4ef3SDoug Ambrisko case BIO_READ:
2144c33ce503SKonstantin Belousov flags = MFI_CMD_DATAIN | MFI_CMD_BIO;
214558ef3154SDoug Ambrisko readop = 1;
21460d9a4ef3SDoug Ambrisko break;
21470d9a4ef3SDoug Ambrisko case BIO_WRITE:
2148c33ce503SKonstantin Belousov flags = MFI_CMD_DATAOUT | MFI_CMD_BIO;
214958ef3154SDoug Ambrisko readop = 0;
21500d9a4ef3SDoug Ambrisko break;
21510d9a4ef3SDoug Ambrisko default:
2152808df726SXin LI /* TODO: what about BIO_DELETE??? */
2153d176b803SScott Long biofinish(bio, NULL, EOPNOTSUPP);
2154d176b803SScott Long mfi_enqueue_free(cm);
2155d176b803SScott Long return (NULL);
21562e21a3efSScott Long }
21572e21a3efSScott Long
21580d9a4ef3SDoug Ambrisko /* Cheat with the sector length to avoid a non-constant division */
2159057b4402SPedro F. Giffuni blkcount = howmany(bio->bio_bcount, MFI_SECTOR_LEN);
21600d9a4ef3SDoug Ambrisko /* Fill the LBA and Transfer length in CDB */
216158ef3154SDoug Ambrisko cdb_len = mfi_build_cdb(readop, 0, bio->bio_pblkno, blkcount,
216258ef3154SDoug Ambrisko pass->cdb);
21630d9a4ef3SDoug Ambrisko pass->header.target_id = (uintptr_t)bio->bio_driver1;
216458ef3154SDoug Ambrisko pass->header.lun_id = 0;
21650d9a4ef3SDoug Ambrisko pass->header.timeout = 0;
21660d9a4ef3SDoug Ambrisko pass->header.flags = 0;
21670d9a4ef3SDoug Ambrisko pass->header.scsi_status = 0;
21680d9a4ef3SDoug Ambrisko pass->header.sense_len = MFI_SENSE_LEN;
21690d9a4ef3SDoug Ambrisko pass->header.data_len = bio->bio_bcount;
2170808df726SXin LI pass->header.cdb_len = cdb_len;
2171a6ba0fd6SDoug Ambrisko pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2172a6ba0fd6SDoug Ambrisko pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
21730d9a4ef3SDoug Ambrisko cm->cm_complete = mfi_bio_complete;
21740d9a4ef3SDoug Ambrisko cm->cm_private = bio;
2175c33ce503SKonstantin Belousov cm->cm_data = unmapped_buf;
21760d9a4ef3SDoug Ambrisko cm->cm_len = bio->bio_bcount;
21770d9a4ef3SDoug Ambrisko cm->cm_sg = &pass->sgl;
21780d9a4ef3SDoug Ambrisko cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
21790d9a4ef3SDoug Ambrisko cm->cm_flags = flags;
218008c89430SSteven Hartland
21810d9a4ef3SDoug Ambrisko return (cm);
21820d9a4ef3SDoug Ambrisko }
21830d9a4ef3SDoug Ambrisko
21840d9a4ef3SDoug Ambrisko static struct mfi_command *
mfi_build_ldio(struct mfi_softc * sc,struct bio * bio)21850d9a4ef3SDoug Ambrisko mfi_build_ldio(struct mfi_softc *sc, struct bio *bio)
21860d9a4ef3SDoug Ambrisko {
21870d9a4ef3SDoug Ambrisko struct mfi_io_frame *io;
21880d9a4ef3SDoug Ambrisko struct mfi_command *cm;
2189808df726SXin LI int flags;
2190808df726SXin LI uint32_t blkcount;
21910d9a4ef3SDoug Ambrisko uint32_t context = 0;
21920d9a4ef3SDoug Ambrisko
219308c89430SSteven Hartland mtx_assert(&sc->mfi_io_lock, MA_OWNED);
219408c89430SSteven Hartland
21950d9a4ef3SDoug Ambrisko if ((cm = mfi_dequeue_free(sc)) == NULL)
21960d9a4ef3SDoug Ambrisko return (NULL);
21970d9a4ef3SDoug Ambrisko
21980d9a4ef3SDoug Ambrisko /* Zero out the MFI frame */
21990d9a4ef3SDoug Ambrisko context = cm->cm_frame->header.context;
22000d9a4ef3SDoug Ambrisko bzero(cm->cm_frame, sizeof(union mfi_frame));
22010d9a4ef3SDoug Ambrisko cm->cm_frame->header.context = context;
22022e21a3efSScott Long io = &cm->cm_frame->io;
2203225e4b42SWarner Losh switch (bio->bio_cmd) {
22042e21a3efSScott Long case BIO_READ:
22052e21a3efSScott Long io->header.cmd = MFI_CMD_LD_READ;
2206c33ce503SKonstantin Belousov flags = MFI_CMD_DATAIN | MFI_CMD_BIO;
22072e21a3efSScott Long break;
22082e21a3efSScott Long case BIO_WRITE:
22092e21a3efSScott Long io->header.cmd = MFI_CMD_LD_WRITE;
2210c33ce503SKonstantin Belousov flags = MFI_CMD_DATAOUT | MFI_CMD_BIO;
22112e21a3efSScott Long break;
22122e21a3efSScott Long default:
2213808df726SXin LI /* TODO: what about BIO_DELETE??? */
2214d176b803SScott Long biofinish(bio, NULL, EOPNOTSUPP);
2215d176b803SScott Long mfi_enqueue_free(cm);
2216d176b803SScott Long return (NULL);
22172e21a3efSScott Long }
22182e21a3efSScott Long
22192e21a3efSScott Long /* Cheat with the sector length to avoid a non-constant division */
2220057b4402SPedro F. Giffuni blkcount = howmany(bio->bio_bcount, MFI_SECTOR_LEN);
22212e21a3efSScott Long io->header.target_id = (uintptr_t)bio->bio_driver1;
22222e21a3efSScott Long io->header.timeout = 0;
22232e21a3efSScott Long io->header.flags = 0;
22240d9a4ef3SDoug Ambrisko io->header.scsi_status = 0;
22252e21a3efSScott Long io->header.sense_len = MFI_SENSE_LEN;
22262e21a3efSScott Long io->header.data_len = blkcount;
2227a6ba0fd6SDoug Ambrisko io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2228a6ba0fd6SDoug Ambrisko io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
22292e21a3efSScott Long io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
22302e21a3efSScott Long io->lba_lo = bio->bio_pblkno & 0xffffffff;
22312e21a3efSScott Long cm->cm_complete = mfi_bio_complete;
22322e21a3efSScott Long cm->cm_private = bio;
2233c33ce503SKonstantin Belousov cm->cm_data = unmapped_buf;
22342e21a3efSScott Long cm->cm_len = bio->bio_bcount;
22352e21a3efSScott Long cm->cm_sg = &io->sgl;
22362e21a3efSScott Long cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
22372e21a3efSScott Long cm->cm_flags = flags;
223808c89430SSteven Hartland
22392e21a3efSScott Long return (cm);
22402e21a3efSScott Long }
22412e21a3efSScott Long
22422e21a3efSScott Long static void
mfi_bio_complete(struct mfi_command * cm)22432e21a3efSScott Long mfi_bio_complete(struct mfi_command *cm)
22442e21a3efSScott Long {
22452e21a3efSScott Long struct bio *bio;
22462e21a3efSScott Long struct mfi_frame_header *hdr;
22472e21a3efSScott Long struct mfi_softc *sc;
22482e21a3efSScott Long
22492e21a3efSScott Long bio = cm->cm_private;
22502e21a3efSScott Long hdr = &cm->cm_frame->header;
22512e21a3efSScott Long sc = cm->cm_sc;
22522e21a3efSScott Long
2253c2e3261aSJohn Baldwin if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) {
22542e21a3efSScott Long bio->bio_flags |= BIO_ERROR;
22552e21a3efSScott Long bio->bio_error = EIO;
225608c89430SSteven Hartland device_printf(sc->mfi_dev, "I/O error, cmd=%p, status=%#x, "
225708c89430SSteven Hartland "scsi_status=%#x\n", cm, hdr->cmd_status, hdr->scsi_status);
22582e21a3efSScott Long mfi_print_sense(cm->cm_sc, cm->cm_sense);
2259fa1e6ef4SDoug Ambrisko } else if (cm->cm_error != 0) {
2260fa1e6ef4SDoug Ambrisko bio->bio_flags |= BIO_ERROR;
226108c89430SSteven Hartland bio->bio_error = cm->cm_error;
226208c89430SSteven Hartland device_printf(sc->mfi_dev, "I/O error, cmd=%p, error=%#x\n",
226308c89430SSteven Hartland cm, cm->cm_error);
22642e21a3efSScott Long }
22652e21a3efSScott Long
22662e21a3efSScott Long mfi_release_command(cm);
22672e21a3efSScott Long mfi_disk_complete(bio);
22682e21a3efSScott Long }
22692e21a3efSScott Long
22702e21a3efSScott Long void
mfi_startio(struct mfi_softc * sc)22712e21a3efSScott Long mfi_startio(struct mfi_softc *sc)
22722e21a3efSScott Long {
22732e21a3efSScott Long struct mfi_command *cm;
227435ef86f2SScott Long struct ccb_hdr *ccbh;
22752e21a3efSScott Long
22762e21a3efSScott Long for (;;) {
22772e21a3efSScott Long /* Don't bother if we're short on resources */
22782e21a3efSScott Long if (sc->mfi_flags & MFI_FLAGS_QFRZN)
22792e21a3efSScott Long break;
22802e21a3efSScott Long
22812e21a3efSScott Long /* Try a command that has already been prepared */
22822e21a3efSScott Long cm = mfi_dequeue_ready(sc);
22832e21a3efSScott Long
228435ef86f2SScott Long if (cm == NULL) {
228535ef86f2SScott Long if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL)
228635ef86f2SScott Long cm = sc->mfi_cam_start(ccbh);
228735ef86f2SScott Long }
228835ef86f2SScott Long
22892e21a3efSScott Long /* Nope, so look for work on the bioq */
22902e21a3efSScott Long if (cm == NULL)
22912e21a3efSScott Long cm = mfi_bio_command(sc);
22922e21a3efSScott Long
22932e21a3efSScott Long /* No work available, so exit */
22942e21a3efSScott Long if (cm == NULL)
22952e21a3efSScott Long break;
22962e21a3efSScott Long
22972e21a3efSScott Long /* Send the command to the controller */
22982e21a3efSScott Long if (mfi_mapcmd(sc, cm) != 0) {
229908c89430SSteven Hartland device_printf(sc->mfi_dev, "Failed to startio\n");
23002e21a3efSScott Long mfi_requeue_ready(cm);
23012e21a3efSScott Long break;
23022e21a3efSScott Long }
23032e21a3efSScott Long }
23042e21a3efSScott Long }
23052e21a3efSScott Long
23060d9a4ef3SDoug Ambrisko int
mfi_mapcmd(struct mfi_softc * sc,struct mfi_command * cm)23072e21a3efSScott Long mfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
23082e21a3efSScott Long {
23092e21a3efSScott Long int error, polled;
23102e21a3efSScott Long
2311441f6d5dSScott Long mtx_assert(&sc->mfi_io_lock, MA_OWNED);
2312441f6d5dSScott Long
23130d9a4ef3SDoug Ambrisko if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) {
23142e21a3efSScott Long polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
2315dd0b4fb6SKonstantin Belousov if (cm->cm_flags & MFI_CMD_CCB)
2316dd0b4fb6SKonstantin Belousov error = bus_dmamap_load_ccb(sc->mfi_buffer_dmat,
2317dd0b4fb6SKonstantin Belousov cm->cm_dmamap, cm->cm_data, mfi_data_cb, cm,
2318dd0b4fb6SKonstantin Belousov polled);
2319c33ce503SKonstantin Belousov else if (cm->cm_flags & MFI_CMD_BIO)
2320c33ce503SKonstantin Belousov error = bus_dmamap_load_bio(sc->mfi_buffer_dmat,
2321c33ce503SKonstantin Belousov cm->cm_dmamap, cm->cm_private, mfi_data_cb, cm,
2322c33ce503SKonstantin Belousov polled);
2323dd0b4fb6SKonstantin Belousov else
2324dd0b4fb6SKonstantin Belousov error = bus_dmamap_load(sc->mfi_buffer_dmat,
2325dd0b4fb6SKonstantin Belousov cm->cm_dmamap, cm->cm_data, cm->cm_len,
2326dd0b4fb6SKonstantin Belousov mfi_data_cb, cm, polled);
23272e21a3efSScott Long if (error == EINPROGRESS) {
23282e21a3efSScott Long sc->mfi_flags |= MFI_FLAGS_QFRZN;
23292e21a3efSScott Long return (0);
23302e21a3efSScott Long }
23312e21a3efSScott Long } else {
23322e21a3efSScott Long error = mfi_send_frame(sc, cm);
23332e21a3efSScott Long }
23342e21a3efSScott Long
23352e21a3efSScott Long return (error);
23362e21a3efSScott Long }
23372e21a3efSScott Long
23382e21a3efSScott Long static void
mfi_data_cb(void * arg,bus_dma_segment_t * segs,int nsegs,int error)23392e21a3efSScott Long mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
23402e21a3efSScott Long {
23412e21a3efSScott Long struct mfi_frame_header *hdr;
23422e21a3efSScott Long struct mfi_command *cm;
2343aab58269SScott Long union mfi_sgl *sgl;
23442e21a3efSScott Long struct mfi_softc *sc;
23455f8ad41cSAlexander Motin int i, j, first, dir;
234608c89430SSteven Hartland int sge_size, locked;
23472e21a3efSScott Long
23482e21a3efSScott Long cm = (struct mfi_command *)arg;
23492e21a3efSScott Long sc = cm->cm_sc;
2350aab58269SScott Long hdr = &cm->cm_frame->header;
2351aab58269SScott Long sgl = cm->cm_sg;
23522e21a3efSScott Long
235308c89430SSteven Hartland /*
235408c89430SSteven Hartland * We need to check if we have the lock as this is async
235508c89430SSteven Hartland * callback so even though our caller mfi_mapcmd asserts
2356453130d9SPedro F. Giffuni * it has the lock, there is no guarantee that hasn't been
235708c89430SSteven Hartland * dropped if bus_dmamap_load returned prior to our
235808c89430SSteven Hartland * completion.
235908c89430SSteven Hartland */
236008c89430SSteven Hartland if ((locked = mtx_owned(&sc->mfi_io_lock)) == 0)
236108c89430SSteven Hartland mtx_lock(&sc->mfi_io_lock);
236208c89430SSteven Hartland
23635be25877SDoug Ambrisko if (error) {
23645be25877SDoug Ambrisko printf("error %d in callback\n", error);
23655be25877SDoug Ambrisko cm->cm_error = error;
23665be25877SDoug Ambrisko mfi_complete(sc, cm);
236708c89430SSteven Hartland goto out;
23685be25877SDoug Ambrisko }
23690d9a4ef3SDoug Ambrisko /* Use IEEE sgl only for IO's on a SKINNY controller
23700d9a4ef3SDoug Ambrisko * For other commands on a SKINNY controller use either
23710d9a4ef3SDoug Ambrisko * sg32 or sg64 based on the sizeof(bus_addr_t).
23720d9a4ef3SDoug Ambrisko * Also calculate the total frame size based on the type
23730d9a4ef3SDoug Ambrisko * of SGL used.
23740d9a4ef3SDoug Ambrisko */
23750d9a4ef3SDoug Ambrisko if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) ||
23760d9a4ef3SDoug Ambrisko (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) ||
23770d9a4ef3SDoug Ambrisko (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) &&
23780d9a4ef3SDoug Ambrisko (sc->mfi_flags & MFI_FLAGS_SKINNY)) {
23790d9a4ef3SDoug Ambrisko for (i = 0; i < nsegs; i++) {
23800d9a4ef3SDoug Ambrisko sgl->sg_skinny[i].addr = segs[i].ds_addr;
23810d9a4ef3SDoug Ambrisko sgl->sg_skinny[i].len = segs[i].ds_len;
23820d9a4ef3SDoug Ambrisko sgl->sg_skinny[i].flag = 0;
23830d9a4ef3SDoug Ambrisko }
23840d9a4ef3SDoug Ambrisko hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64;
23850d9a4ef3SDoug Ambrisko sge_size = sizeof(struct mfi_sg_skinny);
2386a6ba0fd6SDoug Ambrisko hdr->sg_count = nsegs;
23870d9a4ef3SDoug Ambrisko } else {
23885f8ad41cSAlexander Motin j = 0;
23895f8ad41cSAlexander Motin if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
23905f8ad41cSAlexander Motin first = cm->cm_stp_len;
23915f8ad41cSAlexander Motin if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
23925f8ad41cSAlexander Motin sgl->sg32[j].addr = segs[0].ds_addr;
23935f8ad41cSAlexander Motin sgl->sg32[j++].len = first;
23945f8ad41cSAlexander Motin } else {
23955f8ad41cSAlexander Motin sgl->sg64[j].addr = segs[0].ds_addr;
23965f8ad41cSAlexander Motin sgl->sg64[j++].len = first;
23975f8ad41cSAlexander Motin }
23985f8ad41cSAlexander Motin } else
23995f8ad41cSAlexander Motin first = 0;
2400aab58269SScott Long if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
24012e21a3efSScott Long for (i = 0; i < nsegs; i++) {
24025f8ad41cSAlexander Motin sgl->sg32[j].addr = segs[i].ds_addr + first;
24035f8ad41cSAlexander Motin sgl->sg32[j++].len = segs[i].ds_len - first;
24045f8ad41cSAlexander Motin first = 0;
24052e21a3efSScott Long }
2406aab58269SScott Long } else {
2407aab58269SScott Long for (i = 0; i < nsegs; i++) {
24085f8ad41cSAlexander Motin sgl->sg64[j].addr = segs[i].ds_addr + first;
24095f8ad41cSAlexander Motin sgl->sg64[j++].len = segs[i].ds_len - first;
24105f8ad41cSAlexander Motin first = 0;
2411aab58269SScott Long }
2412aab58269SScott Long hdr->flags |= MFI_FRAME_SGL64;
24132e21a3efSScott Long }
24145f8ad41cSAlexander Motin hdr->sg_count = j;
2415a6ba0fd6SDoug Ambrisko sge_size = sc->mfi_sge_size;
24160d9a4ef3SDoug Ambrisko }
24172e21a3efSScott Long
24182e21a3efSScott Long dir = 0;
24192e21a3efSScott Long if (cm->cm_flags & MFI_CMD_DATAIN) {
24202e21a3efSScott Long dir |= BUS_DMASYNC_PREREAD;
24212e21a3efSScott Long hdr->flags |= MFI_FRAME_DIR_READ;
24222e21a3efSScott Long }
24232e21a3efSScott Long if (cm->cm_flags & MFI_CMD_DATAOUT) {
24242e21a3efSScott Long dir |= BUS_DMASYNC_PREWRITE;
24252e21a3efSScott Long hdr->flags |= MFI_FRAME_DIR_WRITE;
24262e21a3efSScott Long }
24272e21a3efSScott Long bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
24282e21a3efSScott Long cm->cm_flags |= MFI_CMD_MAPPED;
24292e21a3efSScott Long
24302e21a3efSScott Long /*
24312e21a3efSScott Long * Instead of calculating the total number of frames in the
24322e21a3efSScott Long * compound frame, it's already assumed that there will be at
24332e21a3efSScott Long * least 1 frame, so don't compensate for the modulo of the
24342e21a3efSScott Long * following division.
24352e21a3efSScott Long */
24366ef1ad0dSScott Long cm->cm_total_frame_size += (sge_size * nsegs);
24372e21a3efSScott Long cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
24382e21a3efSScott Long
243908c89430SSteven Hartland if ((error = mfi_send_frame(sc, cm)) != 0) {
244008c89430SSteven Hartland printf("error %d in callback from mfi_send_frame\n", error);
244108c89430SSteven Hartland cm->cm_error = error;
244208c89430SSteven Hartland mfi_complete(sc, cm);
244308c89430SSteven Hartland goto out;
244408c89430SSteven Hartland }
244508c89430SSteven Hartland
244608c89430SSteven Hartland out:
244708c89430SSteven Hartland /* leave the lock in the state we found it */
244808c89430SSteven Hartland if (locked == 0)
244908c89430SSteven Hartland mtx_unlock(&sc->mfi_io_lock);
24502e21a3efSScott Long
24512e21a3efSScott Long return;
24522e21a3efSScott Long }
24532e21a3efSScott Long
24542e21a3efSScott Long static int
mfi_send_frame(struct mfi_softc * sc,struct mfi_command * cm)24552e21a3efSScott Long mfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
24562e21a3efSScott Long {
245708c89430SSteven Hartland int error;
245808c89430SSteven Hartland
245908c89430SSteven Hartland mtx_assert(&sc->mfi_io_lock, MA_OWNED);
246008c89430SSteven Hartland
246108c89430SSteven Hartland if (sc->MFA_enabled)
246208c89430SSteven Hartland error = mfi_tbolt_send_frame(sc, cm);
246308c89430SSteven Hartland else
246408c89430SSteven Hartland error = mfi_std_send_frame(sc, cm);
246508c89430SSteven Hartland
246608c89430SSteven Hartland if (error != 0 && (cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0)
246708c89430SSteven Hartland mfi_remove_busy(cm);
246808c89430SSteven Hartland
246908c89430SSteven Hartland return (error);
247008c89430SSteven Hartland }
247108c89430SSteven Hartland
247208c89430SSteven Hartland static int
mfi_std_send_frame(struct mfi_softc * sc,struct mfi_command * cm)247308c89430SSteven Hartland mfi_std_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
247408c89430SSteven Hartland {
24753c77cee1SScott Long struct mfi_frame_header *hdr;
247608c89430SSteven Hartland int tm = mfi_polled_cmd_timeout * 1000;
24773c77cee1SScott Long
24783c77cee1SScott Long hdr = &cm->cm_frame->header;
24793c77cee1SScott Long
24803c77cee1SScott Long if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
24813c77cee1SScott Long cm->cm_timestamp = time_uptime;
24823c77cee1SScott Long mfi_enqueue_busy(cm);
24833c77cee1SScott Long } else {
2484c2e3261aSJohn Baldwin hdr->cmd_status = MFI_STAT_INVALID_STATUS;
24853c77cee1SScott Long hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
24863c77cee1SScott Long }
24872e21a3efSScott Long
24882e21a3efSScott Long /*
24892e21a3efSScott Long * The bus address of the command is aligned on a 64 byte boundary,
24902e21a3efSScott Long * leaving the least 6 bits as zero. For whatever reason, the
24912e21a3efSScott Long * hardware wants the address shifted right by three, leaving just
249278e36c27SScott Long * 3 zero bits. These three bits are then used as a prefetching
249378e36c27SScott Long * hint for the hardware to predict how many frames need to be
249478e36c27SScott Long * fetched across the bus. If a command has more than 8 frames
249578e36c27SScott Long * then the 3 bits are set to 0x7 and the firmware uses other
249678e36c27SScott Long * information in the command to determine the total amount to fetch.
249778e36c27SScott Long * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames
249878e36c27SScott Long * is enough for both 32bit and 64bit systems.
24992e21a3efSScott Long */
250078e36c27SScott Long if (cm->cm_extra_frames > 7)
250178e36c27SScott Long cm->cm_extra_frames = 7;
250278e36c27SScott Long
2503610f2ef3SScott Long sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames);
25043c77cee1SScott Long
25053c77cee1SScott Long if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
25063c77cee1SScott Long return (0);
25073c77cee1SScott Long
25083c77cee1SScott Long /* This is a polled command, so busy-wait for it to complete. */
2509c2e3261aSJohn Baldwin while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
25103c77cee1SScott Long DELAY(1000);
2511812819c7SDoug Ambrisko tm -= 1;
25123c77cee1SScott Long if (tm <= 0)
25133c77cee1SScott Long break;
25143c77cee1SScott Long }
25153c77cee1SScott Long
2516c2e3261aSJohn Baldwin if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
2517812819c7SDoug Ambrisko device_printf(sc->mfi_dev, "Frame %p timed out "
2518812819c7SDoug Ambrisko "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
25193c77cee1SScott Long return (ETIMEDOUT);
25203c77cee1SScott Long }
25213c77cee1SScott Long
25222e21a3efSScott Long return (0);
25232e21a3efSScott Long }
25242e21a3efSScott Long
25250d9a4ef3SDoug Ambrisko void
mfi_complete(struct mfi_softc * sc,struct mfi_command * cm)25262e21a3efSScott Long mfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
25272e21a3efSScott Long {
25282e21a3efSScott Long int dir;
252908c89430SSteven Hartland mtx_assert(&sc->mfi_io_lock, MA_OWNED);
25302e21a3efSScott Long
25312e21a3efSScott Long if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) {
25322e21a3efSScott Long dir = 0;
25335f8ad41cSAlexander Motin if ((cm->cm_flags & MFI_CMD_DATAIN) ||
25345f8ad41cSAlexander Motin (cm->cm_frame->header.cmd == MFI_CMD_STP))
25352e21a3efSScott Long dir |= BUS_DMASYNC_POSTREAD;
25362e21a3efSScott Long if (cm->cm_flags & MFI_CMD_DATAOUT)
25372e21a3efSScott Long dir |= BUS_DMASYNC_POSTWRITE;
25382e21a3efSScott Long
25392e21a3efSScott Long bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
25402e21a3efSScott Long bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
25412e21a3efSScott Long cm->cm_flags &= ~MFI_CMD_MAPPED;
25422e21a3efSScott Long }
25432e21a3efSScott Long
25445be25877SDoug Ambrisko cm->cm_flags |= MFI_CMD_COMPLETED;
25455be25877SDoug Ambrisko
25462e21a3efSScott Long if (cm->cm_complete != NULL)
25472e21a3efSScott Long cm->cm_complete(cm);
2548c0b332d1SPaul Saab else
2549c0b332d1SPaul Saab wakeup(cm);
25502e21a3efSScott Long }
25512e21a3efSScott Long
2552741367d5SDoug Ambrisko static int
mfi_abort(struct mfi_softc * sc,struct mfi_command ** cm_abort)255358ef3154SDoug Ambrisko mfi_abort(struct mfi_softc *sc, struct mfi_command **cm_abort)
2554741367d5SDoug Ambrisko {
2555741367d5SDoug Ambrisko struct mfi_command *cm;
2556741367d5SDoug Ambrisko struct mfi_abort_frame *abort;
255708c89430SSteven Hartland int i = 0, error;
25580d9a4ef3SDoug Ambrisko uint32_t context = 0;
2559741367d5SDoug Ambrisko
256058ef3154SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
2561741367d5SDoug Ambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) {
256208c89430SSteven Hartland mtx_unlock(&sc->mfi_io_lock);
2563741367d5SDoug Ambrisko return (EBUSY);
2564741367d5SDoug Ambrisko }
2565741367d5SDoug Ambrisko
25660d9a4ef3SDoug Ambrisko /* Zero out the MFI frame */
25670d9a4ef3SDoug Ambrisko context = cm->cm_frame->header.context;
25680d9a4ef3SDoug Ambrisko bzero(cm->cm_frame, sizeof(union mfi_frame));
25690d9a4ef3SDoug Ambrisko cm->cm_frame->header.context = context;
25700d9a4ef3SDoug Ambrisko
2571741367d5SDoug Ambrisko abort = &cm->cm_frame->abort;
2572741367d5SDoug Ambrisko abort->header.cmd = MFI_CMD_ABORT;
2573741367d5SDoug Ambrisko abort->header.flags = 0;
25740d9a4ef3SDoug Ambrisko abort->header.scsi_status = 0;
257558ef3154SDoug Ambrisko abort->abort_context = (*cm_abort)->cm_frame->header.context;
257658ef3154SDoug Ambrisko abort->abort_mfi_addr_lo = (uint32_t)(*cm_abort)->cm_frame_busaddr;
2577a6ba0fd6SDoug Ambrisko abort->abort_mfi_addr_hi =
257858ef3154SDoug Ambrisko (uint32_t)((uint64_t)(*cm_abort)->cm_frame_busaddr >> 32);
2579741367d5SDoug Ambrisko cm->cm_data = NULL;
25803c77cee1SScott Long cm->cm_flags = MFI_CMD_POLLED;
2581741367d5SDoug Ambrisko
258208c89430SSteven Hartland if ((error = mfi_mapcmd(sc, cm)) != 0)
258308c89430SSteven Hartland device_printf(sc->mfi_dev, "failed to abort command\n");
2584741367d5SDoug Ambrisko mfi_release_command(cm);
2585741367d5SDoug Ambrisko
258658ef3154SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
258758ef3154SDoug Ambrisko while (i < 5 && *cm_abort != NULL) {
258858ef3154SDoug Ambrisko tsleep(cm_abort, 0, "mfiabort",
2589a6ba0fd6SDoug Ambrisko 5 * hz);
2590812819c7SDoug Ambrisko i++;
2591741367d5SDoug Ambrisko }
259258ef3154SDoug Ambrisko if (*cm_abort != NULL) {
259358ef3154SDoug Ambrisko /* Force a complete if command didn't abort */
259458ef3154SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
259558ef3154SDoug Ambrisko (*cm_abort)->cm_complete(*cm_abort);
259658ef3154SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
2597ddbffe7fSDoug Ambrisko }
2598741367d5SDoug Ambrisko
259908c89430SSteven Hartland return (error);
2600741367d5SDoug Ambrisko }
2601741367d5SDoug Ambrisko
26022e21a3efSScott Long int
mfi_dump_blocks(struct mfi_softc * sc,int id,uint64_t lba,void * virt,int len)2603a6ba0fd6SDoug Ambrisko mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2604a6ba0fd6SDoug Ambrisko int len)
26052e21a3efSScott Long {
26062e21a3efSScott Long struct mfi_command *cm;
26072e21a3efSScott Long struct mfi_io_frame *io;
26082e21a3efSScott Long int error;
26090d9a4ef3SDoug Ambrisko uint32_t context = 0;
26102e21a3efSScott Long
26112e21a3efSScott Long if ((cm = mfi_dequeue_free(sc)) == NULL)
26122e21a3efSScott Long return (EBUSY);
26132e21a3efSScott Long
26140d9a4ef3SDoug Ambrisko /* Zero out the MFI frame */
26150d9a4ef3SDoug Ambrisko context = cm->cm_frame->header.context;
26160d9a4ef3SDoug Ambrisko bzero(cm->cm_frame, sizeof(union mfi_frame));
26170d9a4ef3SDoug Ambrisko cm->cm_frame->header.context = context;
26180d9a4ef3SDoug Ambrisko
26192e21a3efSScott Long io = &cm->cm_frame->io;
26202e21a3efSScott Long io->header.cmd = MFI_CMD_LD_WRITE;
26212e21a3efSScott Long io->header.target_id = id;
26222e21a3efSScott Long io->header.timeout = 0;
26232e21a3efSScott Long io->header.flags = 0;
26240d9a4ef3SDoug Ambrisko io->header.scsi_status = 0;
26252e21a3efSScott Long io->header.sense_len = MFI_SENSE_LEN;
2626057b4402SPedro F. Giffuni io->header.data_len = howmany(len, MFI_SECTOR_LEN);
2627a6ba0fd6SDoug Ambrisko io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2628a6ba0fd6SDoug Ambrisko io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
26292e21a3efSScott Long io->lba_hi = (lba & 0xffffffff00000000) >> 32;
26302e21a3efSScott Long io->lba_lo = lba & 0xffffffff;
26312e21a3efSScott Long cm->cm_data = virt;
26322e21a3efSScott Long cm->cm_len = len;
26332e21a3efSScott Long cm->cm_sg = &io->sgl;
26342e21a3efSScott Long cm->cm_total_frame_size = MFI_IO_FRAME_SIZE;
26352e21a3efSScott Long cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
26362e21a3efSScott Long
263708c89430SSteven Hartland if ((error = mfi_mapcmd(sc, cm)) != 0)
263808c89430SSteven Hartland device_printf(sc->mfi_dev, "failed dump blocks\n");
26392e21a3efSScott Long bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
26402e21a3efSScott Long BUS_DMASYNC_POSTWRITE);
26412e21a3efSScott Long bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
26422e21a3efSScott Long mfi_release_command(cm);
26432e21a3efSScott Long
26442e21a3efSScott Long return (error);
26452e21a3efSScott Long }
26462e21a3efSScott Long
26470d9a4ef3SDoug Ambrisko int
mfi_dump_syspd_blocks(struct mfi_softc * sc,int id,uint64_t lba,void * virt,int len)2648a6ba0fd6SDoug Ambrisko mfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
2649a6ba0fd6SDoug Ambrisko int len)
26500d9a4ef3SDoug Ambrisko {
26510d9a4ef3SDoug Ambrisko struct mfi_command *cm;
26520d9a4ef3SDoug Ambrisko struct mfi_pass_frame *pass;
265358ef3154SDoug Ambrisko int error, readop, cdb_len;
2654808df726SXin LI uint32_t blkcount;
26550d9a4ef3SDoug Ambrisko
26560d9a4ef3SDoug Ambrisko if ((cm = mfi_dequeue_free(sc)) == NULL)
26570d9a4ef3SDoug Ambrisko return (EBUSY);
26580d9a4ef3SDoug Ambrisko
26590d9a4ef3SDoug Ambrisko pass = &cm->cm_frame->pass;
26600d9a4ef3SDoug Ambrisko bzero(pass->cdb, 16);
26610d9a4ef3SDoug Ambrisko pass->header.cmd = MFI_CMD_PD_SCSI_IO;
266258ef3154SDoug Ambrisko
266358ef3154SDoug Ambrisko readop = 0;
2664057b4402SPedro F. Giffuni blkcount = howmany(len, MFI_SECTOR_LEN);
266558ef3154SDoug Ambrisko cdb_len = mfi_build_cdb(readop, 0, lba, blkcount, pass->cdb);
26660d9a4ef3SDoug Ambrisko pass->header.target_id = id;
26670d9a4ef3SDoug Ambrisko pass->header.timeout = 0;
26680d9a4ef3SDoug Ambrisko pass->header.flags = 0;
26690d9a4ef3SDoug Ambrisko pass->header.scsi_status = 0;
26700d9a4ef3SDoug Ambrisko pass->header.sense_len = MFI_SENSE_LEN;
26710d9a4ef3SDoug Ambrisko pass->header.data_len = len;
267258ef3154SDoug Ambrisko pass->header.cdb_len = cdb_len;
2673a6ba0fd6SDoug Ambrisko pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
2674a6ba0fd6SDoug Ambrisko pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
26750d9a4ef3SDoug Ambrisko cm->cm_data = virt;
26760d9a4ef3SDoug Ambrisko cm->cm_len = len;
26770d9a4ef3SDoug Ambrisko cm->cm_sg = &pass->sgl;
26780d9a4ef3SDoug Ambrisko cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
267958ef3154SDoug Ambrisko cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT | MFI_CMD_SCSI;
26800d9a4ef3SDoug Ambrisko
268108c89430SSteven Hartland if ((error = mfi_mapcmd(sc, cm)) != 0)
268208c89430SSteven Hartland device_printf(sc->mfi_dev, "failed dump blocks\n");
26830d9a4ef3SDoug Ambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
26840d9a4ef3SDoug Ambrisko BUS_DMASYNC_POSTWRITE);
26850d9a4ef3SDoug Ambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
26860d9a4ef3SDoug Ambrisko mfi_release_command(cm);
26870d9a4ef3SDoug Ambrisko
26880d9a4ef3SDoug Ambrisko return (error);
26890d9a4ef3SDoug Ambrisko }
26900d9a4ef3SDoug Ambrisko
26912e21a3efSScott Long static int
mfi_open(struct cdev * dev,int flags,int fmt,struct thread * td)269200b4e54aSWarner Losh mfi_open(struct cdev *dev, int flags, int fmt, struct thread *td)
26932e21a3efSScott Long {
26942e21a3efSScott Long struct mfi_softc *sc;
2695cde586a7SJohn Baldwin int error;
26962e21a3efSScott Long
26972e21a3efSScott Long sc = dev->si_drv1;
2698441f6d5dSScott Long
2699441f6d5dSScott Long mtx_lock(&sc->mfi_io_lock);
2700cde586a7SJohn Baldwin if (sc->mfi_detaching)
2701cde586a7SJohn Baldwin error = ENXIO;
2702cde586a7SJohn Baldwin else {
27032e21a3efSScott Long sc->mfi_flags |= MFI_FLAGS_OPEN;
2704cde586a7SJohn Baldwin error = 0;
2705cde586a7SJohn Baldwin }
2706441f6d5dSScott Long mtx_unlock(&sc->mfi_io_lock);
27072e21a3efSScott Long
2708cde586a7SJohn Baldwin return (error);
27092e21a3efSScott Long }
27102e21a3efSScott Long
27112e21a3efSScott Long static int
mfi_close(struct cdev * dev,int flags,int fmt,struct thread * td)271200b4e54aSWarner Losh mfi_close(struct cdev *dev, int flags, int fmt, struct thread *td)
27132e21a3efSScott Long {
27142e21a3efSScott Long struct mfi_softc *sc;
2715441f6d5dSScott Long struct mfi_aen *mfi_aen_entry, *tmp;
27162e21a3efSScott Long
27172e21a3efSScott Long sc = dev->si_drv1;
2718441f6d5dSScott Long
2719441f6d5dSScott Long mtx_lock(&sc->mfi_io_lock);
27202e21a3efSScott Long sc->mfi_flags &= ~MFI_FLAGS_OPEN;
27212e21a3efSScott Long
2722441f6d5dSScott Long TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
2723741367d5SDoug Ambrisko if (mfi_aen_entry->p == curproc) {
2724741367d5SDoug Ambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
2725741367d5SDoug Ambrisko aen_link);
2726741367d5SDoug Ambrisko free(mfi_aen_entry, M_MFIBUF);
2727741367d5SDoug Ambrisko }
2728741367d5SDoug Ambrisko }
2729441f6d5dSScott Long mtx_unlock(&sc->mfi_io_lock);
27302e21a3efSScott Long return (0);
27312e21a3efSScott Long }
27322e21a3efSScott Long
27332e21a3efSScott Long static int
mfi_config_lock(struct mfi_softc * sc,uint32_t opcode)27348ec5c98bSJohn Baldwin mfi_config_lock(struct mfi_softc *sc, uint32_t opcode)
27358ec5c98bSJohn Baldwin {
27368ec5c98bSJohn Baldwin
27378ec5c98bSJohn Baldwin switch (opcode) {
27388ec5c98bSJohn Baldwin case MFI_DCMD_LD_DELETE:
27398ec5c98bSJohn Baldwin case MFI_DCMD_CFG_ADD:
27408ec5c98bSJohn Baldwin case MFI_DCMD_CFG_CLEAR:
27417f6194d6SJohn Baldwin case MFI_DCMD_CFG_FOREIGN_IMPORT:
27428ec5c98bSJohn Baldwin sx_xlock(&sc->mfi_config_lock);
27438ec5c98bSJohn Baldwin return (1);
27448ec5c98bSJohn Baldwin default:
27458ec5c98bSJohn Baldwin return (0);
27468ec5c98bSJohn Baldwin }
27478ec5c98bSJohn Baldwin }
27488ec5c98bSJohn Baldwin
27498ec5c98bSJohn Baldwin static void
mfi_config_unlock(struct mfi_softc * sc,int locked)27508ec5c98bSJohn Baldwin mfi_config_unlock(struct mfi_softc *sc, int locked)
27518ec5c98bSJohn Baldwin {
27528ec5c98bSJohn Baldwin
27538ec5c98bSJohn Baldwin if (locked)
27548ec5c98bSJohn Baldwin sx_xunlock(&sc->mfi_config_lock);
27558ec5c98bSJohn Baldwin }
27568ec5c98bSJohn Baldwin
2757a6ba0fd6SDoug Ambrisko /*
2758a6ba0fd6SDoug Ambrisko * Perform pre-issue checks on commands from userland and possibly veto
2759a6ba0fd6SDoug Ambrisko * them.
2760a6ba0fd6SDoug Ambrisko */
27618ec5c98bSJohn Baldwin static int
mfi_check_command_pre(struct mfi_softc * sc,struct mfi_command * cm)27628ec5c98bSJohn Baldwin mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
27638ec5c98bSJohn Baldwin {
27648ec5c98bSJohn Baldwin struct mfi_disk *ld, *ld2;
27658ec5c98bSJohn Baldwin int error;
27660d9a4ef3SDoug Ambrisko struct mfi_system_pd *syspd = NULL;
27670d9a4ef3SDoug Ambrisko uint16_t syspd_id;
27680d9a4ef3SDoug Ambrisko uint16_t *mbox;
27698ec5c98bSJohn Baldwin
27708ec5c98bSJohn Baldwin mtx_assert(&sc->mfi_io_lock, MA_OWNED);
27718ec5c98bSJohn Baldwin error = 0;
27728ec5c98bSJohn Baldwin switch (cm->cm_frame->dcmd.opcode) {
27738ec5c98bSJohn Baldwin case MFI_DCMD_LD_DELETE:
27748ec5c98bSJohn Baldwin TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
27758ec5c98bSJohn Baldwin if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
27768ec5c98bSJohn Baldwin break;
27778ec5c98bSJohn Baldwin }
27788ec5c98bSJohn Baldwin if (ld == NULL)
27798ec5c98bSJohn Baldwin error = ENOENT;
27808ec5c98bSJohn Baldwin else
27818ec5c98bSJohn Baldwin error = mfi_disk_disable(ld);
27828ec5c98bSJohn Baldwin break;
27838ec5c98bSJohn Baldwin case MFI_DCMD_CFG_CLEAR:
27848ec5c98bSJohn Baldwin TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
27858ec5c98bSJohn Baldwin error = mfi_disk_disable(ld);
27868ec5c98bSJohn Baldwin if (error)
27878ec5c98bSJohn Baldwin break;
27888ec5c98bSJohn Baldwin }
27898ec5c98bSJohn Baldwin if (error) {
27908ec5c98bSJohn Baldwin TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) {
27918ec5c98bSJohn Baldwin if (ld2 == ld)
27928ec5c98bSJohn Baldwin break;
27938ec5c98bSJohn Baldwin mfi_disk_enable(ld2);
27948ec5c98bSJohn Baldwin }
27958ec5c98bSJohn Baldwin }
27968ec5c98bSJohn Baldwin break;
27970d9a4ef3SDoug Ambrisko case MFI_DCMD_PD_STATE_SET:
27980d9a4ef3SDoug Ambrisko mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
27990d9a4ef3SDoug Ambrisko syspd_id = mbox[0];
28000d9a4ef3SDoug Ambrisko if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
28010d9a4ef3SDoug Ambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
28020d9a4ef3SDoug Ambrisko if (syspd->pd_id == syspd_id)
28030d9a4ef3SDoug Ambrisko break;
28040d9a4ef3SDoug Ambrisko }
28050d9a4ef3SDoug Ambrisko }
28060d9a4ef3SDoug Ambrisko else
28070d9a4ef3SDoug Ambrisko break;
28080d9a4ef3SDoug Ambrisko if (syspd)
28090d9a4ef3SDoug Ambrisko error = mfi_syspd_disable(syspd);
28100d9a4ef3SDoug Ambrisko break;
28118ec5c98bSJohn Baldwin default:
28128ec5c98bSJohn Baldwin break;
28138ec5c98bSJohn Baldwin }
28148ec5c98bSJohn Baldwin return (error);
28158ec5c98bSJohn Baldwin }
28168ec5c98bSJohn Baldwin
28178ec5c98bSJohn Baldwin /* Perform post-issue checks on commands from userland. */
28188ec5c98bSJohn Baldwin static void
mfi_check_command_post(struct mfi_softc * sc,struct mfi_command * cm)28198ec5c98bSJohn Baldwin mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
28208ec5c98bSJohn Baldwin {
28218ec5c98bSJohn Baldwin struct mfi_disk *ld, *ldn;
28220d9a4ef3SDoug Ambrisko struct mfi_system_pd *syspd = NULL;
28230d9a4ef3SDoug Ambrisko uint16_t syspd_id;
28240d9a4ef3SDoug Ambrisko uint16_t *mbox;
28258ec5c98bSJohn Baldwin
28268ec5c98bSJohn Baldwin switch (cm->cm_frame->dcmd.opcode) {
28278ec5c98bSJohn Baldwin case MFI_DCMD_LD_DELETE:
28288ec5c98bSJohn Baldwin TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
28298ec5c98bSJohn Baldwin if (ld->ld_id == cm->cm_frame->dcmd.mbox[0])
28308ec5c98bSJohn Baldwin break;
28318ec5c98bSJohn Baldwin }
28328ec5c98bSJohn Baldwin KASSERT(ld != NULL, ("volume dissappeared"));
28338ec5c98bSJohn Baldwin if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
28348ec5c98bSJohn Baldwin mtx_unlock(&sc->mfi_io_lock);
2835c6df6f53SWarner Losh bus_topo_lock();
28368ec5c98bSJohn Baldwin device_delete_child(sc->mfi_dev, ld->ld_dev);
2837c6df6f53SWarner Losh bus_topo_unlock();
28388ec5c98bSJohn Baldwin mtx_lock(&sc->mfi_io_lock);
28398ec5c98bSJohn Baldwin } else
28408ec5c98bSJohn Baldwin mfi_disk_enable(ld);
28418ec5c98bSJohn Baldwin break;
28428ec5c98bSJohn Baldwin case MFI_DCMD_CFG_CLEAR:
28438ec5c98bSJohn Baldwin if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
28448ec5c98bSJohn Baldwin mtx_unlock(&sc->mfi_io_lock);
2845c6df6f53SWarner Losh bus_topo_lock();
28468ec5c98bSJohn Baldwin TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) {
28478ec5c98bSJohn Baldwin device_delete_child(sc->mfi_dev, ld->ld_dev);
28488ec5c98bSJohn Baldwin }
2849c6df6f53SWarner Losh bus_topo_unlock();
28508ec5c98bSJohn Baldwin mtx_lock(&sc->mfi_io_lock);
28518ec5c98bSJohn Baldwin } else {
28528ec5c98bSJohn Baldwin TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link)
28538ec5c98bSJohn Baldwin mfi_disk_enable(ld);
28548ec5c98bSJohn Baldwin }
28558ec5c98bSJohn Baldwin break;
28568ec5c98bSJohn Baldwin case MFI_DCMD_CFG_ADD:
28578ec5c98bSJohn Baldwin mfi_ldprobe(sc);
28588ec5c98bSJohn Baldwin break;
2859fa1e6ef4SDoug Ambrisko case MFI_DCMD_CFG_FOREIGN_IMPORT:
2860fa1e6ef4SDoug Ambrisko mfi_ldprobe(sc);
2861fa1e6ef4SDoug Ambrisko break;
28620d9a4ef3SDoug Ambrisko case MFI_DCMD_PD_STATE_SET:
28630d9a4ef3SDoug Ambrisko mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
28640d9a4ef3SDoug Ambrisko syspd_id = mbox[0];
28650d9a4ef3SDoug Ambrisko if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
28660d9a4ef3SDoug Ambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) {
28670d9a4ef3SDoug Ambrisko if (syspd->pd_id == syspd_id)
28680d9a4ef3SDoug Ambrisko break;
28698ec5c98bSJohn Baldwin }
28708ec5c98bSJohn Baldwin }
28710d9a4ef3SDoug Ambrisko else
28720d9a4ef3SDoug Ambrisko break;
28730d9a4ef3SDoug Ambrisko /* If the transition fails then enable the syspd again */
28740d9a4ef3SDoug Ambrisko if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK)
28750d9a4ef3SDoug Ambrisko mfi_syspd_enable(syspd);
28760d9a4ef3SDoug Ambrisko break;
28770d9a4ef3SDoug Ambrisko }
28780d9a4ef3SDoug Ambrisko }
28790d9a4ef3SDoug Ambrisko
288058ef3154SDoug Ambrisko static int
mfi_check_for_sscd(struct mfi_softc * sc,struct mfi_command * cm)288158ef3154SDoug Ambrisko mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm)
28820d9a4ef3SDoug Ambrisko {
288358ef3154SDoug Ambrisko struct mfi_config_data *conf_data;
28840d9a4ef3SDoug Ambrisko struct mfi_command *ld_cm = NULL;
28850d9a4ef3SDoug Ambrisko struct mfi_ld_info *ld_info = NULL;
288658ef3154SDoug Ambrisko struct mfi_ld_config *ld;
288758ef3154SDoug Ambrisko char *p;
28880d9a4ef3SDoug Ambrisko int error = 0;
28890d9a4ef3SDoug Ambrisko
289058ef3154SDoug Ambrisko conf_data = (struct mfi_config_data *)cm->cm_data;
289158ef3154SDoug Ambrisko
289258ef3154SDoug Ambrisko if (cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) {
289358ef3154SDoug Ambrisko p = (char *)conf_data->array;
289458ef3154SDoug Ambrisko p += conf_data->array_size * conf_data->array_count;
289558ef3154SDoug Ambrisko ld = (struct mfi_ld_config *)p;
289658ef3154SDoug Ambrisko if (ld->params.isSSCD == 1)
28970d9a4ef3SDoug Ambrisko error = 1;
28980d9a4ef3SDoug Ambrisko } else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) {
28990d9a4ef3SDoug Ambrisko error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO,
29000d9a4ef3SDoug Ambrisko (void **)&ld_info, sizeof(*ld_info));
29010d9a4ef3SDoug Ambrisko if (error) {
29020d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "Failed to allocate"
29030d9a4ef3SDoug Ambrisko "MFI_DCMD_LD_GET_INFO %d", error);
29040d9a4ef3SDoug Ambrisko if (ld_info)
29050d9a4ef3SDoug Ambrisko free(ld_info, M_MFIBUF);
29060d9a4ef3SDoug Ambrisko return 0;
29070d9a4ef3SDoug Ambrisko }
29080d9a4ef3SDoug Ambrisko ld_cm->cm_flags = MFI_CMD_DATAIN;
29090d9a4ef3SDoug Ambrisko ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0];
29100d9a4ef3SDoug Ambrisko ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0];
29110d9a4ef3SDoug Ambrisko if (mfi_wait_command(sc, ld_cm) != 0) {
29120d9a4ef3SDoug Ambrisko device_printf(sc->mfi_dev, "failed to get log drv\n");
29130d9a4ef3SDoug Ambrisko mfi_release_command(ld_cm);
29140d9a4ef3SDoug Ambrisko free(ld_info, M_MFIBUF);
29150d9a4ef3SDoug Ambrisko return 0;
29160d9a4ef3SDoug Ambrisko }
29170d9a4ef3SDoug Ambrisko
29180d9a4ef3SDoug Ambrisko if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) {
29190d9a4ef3SDoug Ambrisko free(ld_info, M_MFIBUF);
29200d9a4ef3SDoug Ambrisko mfi_release_command(ld_cm);
29210d9a4ef3SDoug Ambrisko return 0;
29220d9a4ef3SDoug Ambrisko }
29230d9a4ef3SDoug Ambrisko else
29240d9a4ef3SDoug Ambrisko ld_info = (struct mfi_ld_info *)ld_cm->cm_private;
29250d9a4ef3SDoug Ambrisko
29260d9a4ef3SDoug Ambrisko if (ld_info->ld_config.params.isSSCD == 1)
29270d9a4ef3SDoug Ambrisko error = 1;
29280d9a4ef3SDoug Ambrisko
29290d9a4ef3SDoug Ambrisko mfi_release_command(ld_cm);
29300d9a4ef3SDoug Ambrisko free(ld_info, M_MFIBUF);
29310d9a4ef3SDoug Ambrisko }
29320d9a4ef3SDoug Ambrisko return error;
29330d9a4ef3SDoug Ambrisko }
29340d9a4ef3SDoug Ambrisko
29350d9a4ef3SDoug Ambrisko static int
mfi_stp_cmd(struct mfi_softc * sc,struct mfi_command * cm,caddr_t arg)29360d9a4ef3SDoug Ambrisko mfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg)
29370d9a4ef3SDoug Ambrisko {
29380d9a4ef3SDoug Ambrisko uint8_t i;
29390d9a4ef3SDoug Ambrisko struct mfi_ioc_packet *ioc;
29400d9a4ef3SDoug Ambrisko ioc = (struct mfi_ioc_packet *)arg;
29410d9a4ef3SDoug Ambrisko int sge_size, error;
29420d9a4ef3SDoug Ambrisko struct megasas_sge *kern_sge;
29430d9a4ef3SDoug Ambrisko
29440d9a4ef3SDoug Ambrisko memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr));
29450d9a4ef3SDoug Ambrisko kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off);
29460d9a4ef3SDoug Ambrisko cm->cm_frame->header.sg_count = ioc->mfi_sge_count;
29470d9a4ef3SDoug Ambrisko
29480d9a4ef3SDoug Ambrisko if (sizeof(bus_addr_t) == 8) {
29490d9a4ef3SDoug Ambrisko cm->cm_frame->header.flags |= MFI_FRAME_SGL64;
29500d9a4ef3SDoug Ambrisko cm->cm_extra_frames = 2;
29510d9a4ef3SDoug Ambrisko sge_size = sizeof(struct mfi_sg64);
29520d9a4ef3SDoug Ambrisko } else {
29530d9a4ef3SDoug Ambrisko cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
29540d9a4ef3SDoug Ambrisko sge_size = sizeof(struct mfi_sg32);
29550d9a4ef3SDoug Ambrisko }
29560d9a4ef3SDoug Ambrisko
29570d9a4ef3SDoug Ambrisko cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count);
2958a6ba0fd6SDoug Ambrisko for (i = 0; i < ioc->mfi_sge_count; i++) {
29590d9a4ef3SDoug Ambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
29600d9a4ef3SDoug Ambrisko 1, 0, /* algnmnt, boundary */
29610d9a4ef3SDoug Ambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
29620d9a4ef3SDoug Ambrisko BUS_SPACE_MAXADDR, /* highaddr */
29630d9a4ef3SDoug Ambrisko NULL, NULL, /* filter, filterarg */
29640d9a4ef3SDoug Ambrisko ioc->mfi_sgl[i].iov_len,/* maxsize */
29650d9a4ef3SDoug Ambrisko 2, /* nsegments */
29660d9a4ef3SDoug Ambrisko ioc->mfi_sgl[i].iov_len,/* maxsegsize */
29670d9a4ef3SDoug Ambrisko BUS_DMA_ALLOCNOW, /* flags */
29680d9a4ef3SDoug Ambrisko NULL, NULL, /* lockfunc, lockarg */
29690d9a4ef3SDoug Ambrisko &sc->mfi_kbuff_arr_dmat[i])) {
2970a6ba0fd6SDoug Ambrisko device_printf(sc->mfi_dev,
2971a6ba0fd6SDoug Ambrisko "Cannot allocate mfi_kbuff_arr_dmat tag\n");
29720d9a4ef3SDoug Ambrisko return (ENOMEM);
29730d9a4ef3SDoug Ambrisko }
29740d9a4ef3SDoug Ambrisko
2975a6ba0fd6SDoug Ambrisko if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i],
2976a6ba0fd6SDoug Ambrisko (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT,
2977a6ba0fd6SDoug Ambrisko &sc->mfi_kbuff_arr_dmamap[i])) {
2978a6ba0fd6SDoug Ambrisko device_printf(sc->mfi_dev,
2979a6ba0fd6SDoug Ambrisko "Cannot allocate mfi_kbuff_arr_dmamap memory\n");
29800d9a4ef3SDoug Ambrisko return (ENOMEM);
29810d9a4ef3SDoug Ambrisko }
29820d9a4ef3SDoug Ambrisko
2983a6ba0fd6SDoug Ambrisko bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i],
2984a6ba0fd6SDoug Ambrisko sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i],
2985a6ba0fd6SDoug Ambrisko ioc->mfi_sgl[i].iov_len, mfi_addr_cb,
2986a6ba0fd6SDoug Ambrisko &sc->mfi_kbuff_arr_busaddr[i], 0);
29870d9a4ef3SDoug Ambrisko
29880d9a4ef3SDoug Ambrisko if (!sc->kbuff_arr[i]) {
2989a6ba0fd6SDoug Ambrisko device_printf(sc->mfi_dev,
2990a6ba0fd6SDoug Ambrisko "Could not allocate memory for kbuff_arr info\n");
29910d9a4ef3SDoug Ambrisko return -1;
29920d9a4ef3SDoug Ambrisko }
29930d9a4ef3SDoug Ambrisko kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i];
29940d9a4ef3SDoug Ambrisko kern_sge[i].length = ioc->mfi_sgl[i].iov_len;
29950d9a4ef3SDoug Ambrisko
29960d9a4ef3SDoug Ambrisko if (sizeof(bus_addr_t) == 8) {
2997a6ba0fd6SDoug Ambrisko cm->cm_frame->stp.sgl.sg64[i].addr =
2998a6ba0fd6SDoug Ambrisko kern_sge[i].phys_addr;
2999a6ba0fd6SDoug Ambrisko cm->cm_frame->stp.sgl.sg64[i].len =
3000a6ba0fd6SDoug Ambrisko ioc->mfi_sgl[i].iov_len;
30010d9a4ef3SDoug Ambrisko } else {
30020e47e251SXin LI cm->cm_frame->stp.sgl.sg32[i].addr =
3003a6ba0fd6SDoug Ambrisko kern_sge[i].phys_addr;
3004a6ba0fd6SDoug Ambrisko cm->cm_frame->stp.sgl.sg32[i].len =
3005a6ba0fd6SDoug Ambrisko ioc->mfi_sgl[i].iov_len;
30060d9a4ef3SDoug Ambrisko }
30070d9a4ef3SDoug Ambrisko
30080d9a4ef3SDoug Ambrisko error = copyin(ioc->mfi_sgl[i].iov_base,
30090d9a4ef3SDoug Ambrisko sc->kbuff_arr[i],
30100d9a4ef3SDoug Ambrisko ioc->mfi_sgl[i].iov_len);
3011a6ba0fd6SDoug Ambrisko if (error != 0) {
3012a6ba0fd6SDoug Ambrisko device_printf(sc->mfi_dev, "Copy in failed\n");
30130d9a4ef3SDoug Ambrisko return error;
30140d9a4ef3SDoug Ambrisko }
30150d9a4ef3SDoug Ambrisko }
30160d9a4ef3SDoug Ambrisko
30170d9a4ef3SDoug Ambrisko cm->cm_flags |=MFI_CMD_MAPPED;
30180d9a4ef3SDoug Ambrisko return 0;
30190d9a4ef3SDoug Ambrisko }
30208ec5c98bSJohn Baldwin
30218ec5c98bSJohn Baldwin static int
mfi_user_command(struct mfi_softc * sc,struct mfi_ioc_passthru * ioc)30220929b669SScott Long mfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc)
30230929b669SScott Long {
30240929b669SScott Long struct mfi_command *cm;
30250929b669SScott Long struct mfi_dcmd_frame *dcmd;
30260929b669SScott Long void *ioc_buf = NULL;
30270929b669SScott Long uint32_t context;
30280929b669SScott Long int error = 0, locked;
30290929b669SScott Long
30300929b669SScott Long if (ioc->buf_size > 0) {
3031da146236SJohn Baldwin if (ioc->buf_size > 1024 * 1024)
30320929b669SScott Long return (ENOMEM);
3033da146236SJohn Baldwin ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK);
30340929b669SScott Long error = copyin(ioc->buf, ioc_buf, ioc->buf_size);
30350929b669SScott Long if (error) {
30360929b669SScott Long device_printf(sc->mfi_dev, "failed to copyin\n");
30370929b669SScott Long free(ioc_buf, M_MFIBUF);
30380929b669SScott Long return (error);
30390929b669SScott Long }
30400929b669SScott Long }
30410929b669SScott Long
30420929b669SScott Long locked = mfi_config_lock(sc, ioc->ioc_frame.opcode);
30430929b669SScott Long
30440929b669SScott Long mtx_lock(&sc->mfi_io_lock);
30450929b669SScott Long while ((cm = mfi_dequeue_free(sc)) == NULL)
30460929b669SScott Long msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz);
30470929b669SScott Long
30480929b669SScott Long /* Save context for later */
30490929b669SScott Long context = cm->cm_frame->header.context;
30500929b669SScott Long
30510929b669SScott Long dcmd = &cm->cm_frame->dcmd;
30520929b669SScott Long bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame));
30530929b669SScott Long
30540929b669SScott Long cm->cm_sg = &dcmd->sgl;
30550929b669SScott Long cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
30560929b669SScott Long cm->cm_data = ioc_buf;
30570929b669SScott Long cm->cm_len = ioc->buf_size;
30580929b669SScott Long
30590929b669SScott Long /* restore context */
30600929b669SScott Long cm->cm_frame->header.context = context;
30610929b669SScott Long
30620929b669SScott Long /* Cheat since we don't know if we're writing or reading */
30630929b669SScott Long cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
30640929b669SScott Long
30650929b669SScott Long error = mfi_check_command_pre(sc, cm);
30660929b669SScott Long if (error)
30670929b669SScott Long goto out;
30680929b669SScott Long
30690929b669SScott Long error = mfi_wait_command(sc, cm);
30700929b669SScott Long if (error) {
30710929b669SScott Long device_printf(sc->mfi_dev, "ioctl failed %d\n", error);
30720929b669SScott Long goto out;
30730929b669SScott Long }
30740929b669SScott Long bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame));
30750929b669SScott Long mfi_check_command_post(sc, cm);
30760929b669SScott Long out:
30770929b669SScott Long mfi_release_command(cm);
30780929b669SScott Long mtx_unlock(&sc->mfi_io_lock);
30790929b669SScott Long mfi_config_unlock(sc, locked);
30800929b669SScott Long if (ioc->buf_size > 0)
30810929b669SScott Long error = copyout(ioc_buf, ioc->buf, ioc->buf_size);
30820929b669SScott Long if (ioc_buf)
30830929b669SScott Long free(ioc_buf, M_MFIBUF);
30840929b669SScott Long return (error);
30850929b669SScott Long }
30860929b669SScott Long
30870929b669SScott Long #define PTRIN(p) ((void *)(uintptr_t)(p))
30880929b669SScott Long
30890929b669SScott Long static int
mfi_ioctl(struct cdev * dev,u_long cmd,caddr_t arg,int flag,struct thread * td)309000b4e54aSWarner Losh mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
30912e21a3efSScott Long {
30922e21a3efSScott Long struct mfi_softc *sc;
30932e21a3efSScott Long union mfi_statrequest *ms;
3094c2be47f2SDoug Ambrisko struct mfi_ioc_packet *ioc;
3095a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
309646fb79eaSDoug Ambrisko struct mfi_ioc_packet32 *ioc32;
309746fb79eaSDoug Ambrisko #endif
3098c2be47f2SDoug Ambrisko struct mfi_ioc_aen *aen;
3099c2be47f2SDoug Ambrisko struct mfi_command *cm = NULL;
31000d9a4ef3SDoug Ambrisko uint32_t context = 0;
3101fa1e6ef4SDoug Ambrisko union mfi_sense_ptr sense_ptr;
31020d9a4ef3SDoug Ambrisko uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0;
31035f8ad41cSAlexander Motin size_t len;
31040d9a4ef3SDoug Ambrisko int i, res;
31050929b669SScott Long struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg;
3106a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
31070929b669SScott Long struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg;
31080929b669SScott Long struct mfi_ioc_passthru iop_swab;
31090929b669SScott Long #endif
31108ec5c98bSJohn Baldwin int error, locked;
31112e21a3efSScott Long sc = dev->si_drv1;
31122e21a3efSScott Long error = 0;
31132e21a3efSScott Long
31140d9a4ef3SDoug Ambrisko if (sc->adpreset)
31150d9a4ef3SDoug Ambrisko return EBUSY;
31160d9a4ef3SDoug Ambrisko
31170d9a4ef3SDoug Ambrisko if (sc->hw_crit_error)
31180d9a4ef3SDoug Ambrisko return EBUSY;
31190d9a4ef3SDoug Ambrisko
31200d9a4ef3SDoug Ambrisko if (sc->issuepend_done == 0)
31210d9a4ef3SDoug Ambrisko return EBUSY;
31220d9a4ef3SDoug Ambrisko
31232e21a3efSScott Long switch (cmd) {
31242e21a3efSScott Long case MFIIO_STATS:
31252e21a3efSScott Long ms = (union mfi_statrequest *)arg;
31262e21a3efSScott Long switch (ms->ms_item) {
31272e21a3efSScott Long case MFIQ_FREE:
31282e21a3efSScott Long case MFIQ_BIO:
31292e21a3efSScott Long case MFIQ_READY:
31302e21a3efSScott Long case MFIQ_BUSY:
31312e21a3efSScott Long bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat,
31322e21a3efSScott Long sizeof(struct mfi_qstat));
31332e21a3efSScott Long break;
31342e21a3efSScott Long default:
3135741367d5SDoug Ambrisko error = ENOIOCTL;
31362e21a3efSScott Long break;
31372e21a3efSScott Long }
31382e21a3efSScott Long break;
3139ddfae47bSScott Long case MFIIO_QUERY_DISK:
3140ddfae47bSScott Long {
3141ddfae47bSScott Long struct mfi_query_disk *qd;
3142ddfae47bSScott Long struct mfi_disk *ld;
3143ddfae47bSScott Long
3144ddfae47bSScott Long qd = (struct mfi_query_disk *)arg;
3145ddfae47bSScott Long mtx_lock(&sc->mfi_io_lock);
3146ddfae47bSScott Long TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
3147ddfae47bSScott Long if (ld->ld_id == qd->array_id)
3148ddfae47bSScott Long break;
3149ddfae47bSScott Long }
3150ddfae47bSScott Long if (ld == NULL) {
3151ddfae47bSScott Long qd->present = 0;
3152ddfae47bSScott Long mtx_unlock(&sc->mfi_io_lock);
3153ddfae47bSScott Long return (0);
3154ddfae47bSScott Long }
3155ddfae47bSScott Long qd->present = 1;
3156ddfae47bSScott Long if (ld->ld_flags & MFI_DISK_FLAGS_OPEN)
3157ddfae47bSScott Long qd->open = 1;
3158ddfae47bSScott Long bzero(qd->devname, SPECNAMELEN + 1);
3159ddfae47bSScott Long snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit);
3160ddfae47bSScott Long mtx_unlock(&sc->mfi_io_lock);
3161ddfae47bSScott Long break;
3162ddfae47bSScott Long }
3163c2be47f2SDoug Ambrisko case MFI_CMD:
3164a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
316546fb79eaSDoug Ambrisko case MFI_CMD32:
316646fb79eaSDoug Ambrisko #endif
3167a355f43eSDoug Ambrisko {
3168a355f43eSDoug Ambrisko devclass_t devclass;
3169c2be47f2SDoug Ambrisko ioc = (struct mfi_ioc_packet *)arg;
3170a355f43eSDoug Ambrisko int adapter;
3171c2be47f2SDoug Ambrisko
3172a355f43eSDoug Ambrisko adapter = ioc->mfi_adapter_no;
3173a355f43eSDoug Ambrisko if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) {
3174a355f43eSDoug Ambrisko devclass = devclass_find("mfi");
3175a355f43eSDoug Ambrisko sc = devclass_get_softc(devclass, adapter);
3176a355f43eSDoug Ambrisko }
3177c2be47f2SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
3178c2be47f2SDoug Ambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) {
3179c2be47f2SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
3180c2be47f2SDoug Ambrisko return (EBUSY);
3181c2be47f2SDoug Ambrisko }
3182c2be47f2SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
31838ec5c98bSJohn Baldwin locked = 0;
3184c2be47f2SDoug Ambrisko
3185c2be47f2SDoug Ambrisko /*
3186c2be47f2SDoug Ambrisko * save off original context since copying from user
3187c2be47f2SDoug Ambrisko * will clobber some data
3188c2be47f2SDoug Ambrisko */
3189c2be47f2SDoug Ambrisko context = cm->cm_frame->header.context;
31900d9a4ef3SDoug Ambrisko cm->cm_frame->header.context = cm->cm_index;
3191c2be47f2SDoug Ambrisko
3192812819c7SDoug Ambrisko bcopy(ioc->mfi_frame.raw, cm->cm_frame,
31930d9a4ef3SDoug Ambrisko 2 * MEGAMFI_FRAME_SIZE);
3194fa1e6ef4SDoug Ambrisko cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3195fa1e6ef4SDoug Ambrisko * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
31960d9a4ef3SDoug Ambrisko cm->cm_frame->header.scsi_status = 0;
31970d9a4ef3SDoug Ambrisko cm->cm_frame->header.pad0 = 0;
319804697de9SDoug Ambrisko if (ioc->mfi_sge_count) {
3199c2be47f2SDoug Ambrisko cm->cm_sg =
3200812819c7SDoug Ambrisko (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
320104697de9SDoug Ambrisko }
320204697de9SDoug Ambrisko cm->cm_flags = 0;
320304697de9SDoug Ambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
320404697de9SDoug Ambrisko cm->cm_flags |= MFI_CMD_DATAIN;
320504697de9SDoug Ambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
320604697de9SDoug Ambrisko cm->cm_flags |= MFI_CMD_DATAOUT;
320704697de9SDoug Ambrisko /* Legacy app shim */
320804697de9SDoug Ambrisko if (cm->cm_flags == 0)
320904697de9SDoug Ambrisko cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
3210c2be47f2SDoug Ambrisko cm->cm_len = cm->cm_frame->header.data_len;
32115f8ad41cSAlexander Motin if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3212a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
32135f8ad41cSAlexander Motin if (cmd == MFI_CMD) {
32145f8ad41cSAlexander Motin #endif
32155f8ad41cSAlexander Motin /* Native */
32165f8ad41cSAlexander Motin cm->cm_stp_len = ioc->mfi_sgl[0].iov_len;
3217a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
32185f8ad41cSAlexander Motin } else {
32195f8ad41cSAlexander Motin /* 32bit on 64bit */
32205f8ad41cSAlexander Motin ioc32 = (struct mfi_ioc_packet32 *)ioc;
32215f8ad41cSAlexander Motin cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len;
32225f8ad41cSAlexander Motin }
32235f8ad41cSAlexander Motin #endif
32245f8ad41cSAlexander Motin cm->cm_len += cm->cm_stp_len;
32255f8ad41cSAlexander Motin }
3226fa1e6ef4SDoug Ambrisko if (cm->cm_len &&
3227fa1e6ef4SDoug Ambrisko (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3228c2be47f2SDoug Ambrisko cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3229c2be47f2SDoug Ambrisko M_WAITOK | M_ZERO);
323004697de9SDoug Ambrisko } else {
323104697de9SDoug Ambrisko cm->cm_data = 0;
323204697de9SDoug Ambrisko }
3233c2be47f2SDoug Ambrisko
3234c2be47f2SDoug Ambrisko /* restore header context */
3235c2be47f2SDoug Ambrisko cm->cm_frame->header.context = context;
3236c2be47f2SDoug Ambrisko
32370d9a4ef3SDoug Ambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
32380d9a4ef3SDoug Ambrisko res = mfi_stp_cmd(sc, cm, arg);
32390d9a4ef3SDoug Ambrisko if (res != 0)
32400d9a4ef3SDoug Ambrisko goto out;
32410d9a4ef3SDoug Ambrisko } else {
3242c2be47f2SDoug Ambrisko temp = data;
32435f8ad41cSAlexander Motin if ((cm->cm_flags & MFI_CMD_DATAOUT) ||
32445f8ad41cSAlexander Motin (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3245812819c7SDoug Ambrisko for (i = 0; i < ioc->mfi_sge_count; i++) {
3246a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
324746fb79eaSDoug Ambrisko if (cmd == MFI_CMD) {
324846fb79eaSDoug Ambrisko #endif
32495f8ad41cSAlexander Motin /* Native */
32505f8ad41cSAlexander Motin addr = ioc->mfi_sgl[i].iov_base;
32515f8ad41cSAlexander Motin len = ioc->mfi_sgl[i].iov_len;
3252a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
32535f8ad41cSAlexander Motin } else {
32545f8ad41cSAlexander Motin /* 32bit on 64bit */
32555f8ad41cSAlexander Motin ioc32 = (struct mfi_ioc_packet32 *)ioc;
32565f8ad41cSAlexander Motin addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
32575f8ad41cSAlexander Motin len = ioc32->mfi_sgl[i].iov_len;
32585f8ad41cSAlexander Motin }
32595f8ad41cSAlexander Motin #endif
32605f8ad41cSAlexander Motin error = copyin(addr, temp, len);
3261c2be47f2SDoug Ambrisko if (error != 0) {
3262c2be47f2SDoug Ambrisko device_printf(sc->mfi_dev,
3263812819c7SDoug Ambrisko "Copy in failed\n");
3264c2be47f2SDoug Ambrisko goto out;
3265c2be47f2SDoug Ambrisko }
32665f8ad41cSAlexander Motin temp = &temp[len];
3267c2be47f2SDoug Ambrisko }
326804697de9SDoug Ambrisko }
32690a158415SDoug Ambrisko }
32700a158415SDoug Ambrisko
3271c2be47f2SDoug Ambrisko if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
3272a6ba0fd6SDoug Ambrisko locked = mfi_config_lock(sc,
3273a6ba0fd6SDoug Ambrisko cm->cm_frame->dcmd.opcode);
3274c2be47f2SDoug Ambrisko
3275c2be47f2SDoug Ambrisko if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3276a6ba0fd6SDoug Ambrisko cm->cm_frame->pass.sense_addr_lo =
3277a6ba0fd6SDoug Ambrisko (uint32_t)cm->cm_sense_busaddr;
3278a6ba0fd6SDoug Ambrisko cm->cm_frame->pass.sense_addr_hi =
3279a6ba0fd6SDoug Ambrisko (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
32808ec5c98bSJohn Baldwin }
3281c2be47f2SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
32820d9a4ef3SDoug Ambrisko skip_pre_post = mfi_check_for_sscd (sc, cm);
32830d9a4ef3SDoug Ambrisko if (!skip_pre_post) {
32848ec5c98bSJohn Baldwin error = mfi_check_command_pre(sc, cm);
32858ec5c98bSJohn Baldwin if (error) {
32868ec5c98bSJohn Baldwin mtx_unlock(&sc->mfi_io_lock);
32878ec5c98bSJohn Baldwin goto out;
32888ec5c98bSJohn Baldwin }
32890d9a4ef3SDoug Ambrisko }
32905be25877SDoug Ambrisko if ((error = mfi_wait_command(sc, cm)) != 0) {
3291c2be47f2SDoug Ambrisko device_printf(sc->mfi_dev,
3292812819c7SDoug Ambrisko "Controller polled failed\n");
3293c2be47f2SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
3294c2be47f2SDoug Ambrisko goto out;
3295c2be47f2SDoug Ambrisko }
32960d9a4ef3SDoug Ambrisko if (!skip_pre_post) {
32978ec5c98bSJohn Baldwin mfi_check_command_post(sc, cm);
32980d9a4ef3SDoug Ambrisko }
3299c2be47f2SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
3300c2be47f2SDoug Ambrisko
33010d9a4ef3SDoug Ambrisko if (cm->cm_frame->header.cmd != MFI_CMD_STP) {
3302c2be47f2SDoug Ambrisko temp = data;
33035f8ad41cSAlexander Motin if ((cm->cm_flags & MFI_CMD_DATAIN) ||
33045f8ad41cSAlexander Motin (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
3305812819c7SDoug Ambrisko for (i = 0; i < ioc->mfi_sge_count; i++) {
3306a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
330746fb79eaSDoug Ambrisko if (cmd == MFI_CMD) {
330846fb79eaSDoug Ambrisko #endif
33095f8ad41cSAlexander Motin /* Native */
33105f8ad41cSAlexander Motin addr = ioc->mfi_sgl[i].iov_base;
33115f8ad41cSAlexander Motin len = ioc->mfi_sgl[i].iov_len;
3312a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
33135f8ad41cSAlexander Motin } else {
33145f8ad41cSAlexander Motin /* 32bit on 64bit */
33155f8ad41cSAlexander Motin ioc32 = (struct mfi_ioc_packet32 *)ioc;
33165f8ad41cSAlexander Motin addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
33175f8ad41cSAlexander Motin len = ioc32->mfi_sgl[i].iov_len;
33185f8ad41cSAlexander Motin }
33195f8ad41cSAlexander Motin #endif
33205f8ad41cSAlexander Motin error = copyout(temp, addr, len);
3321c2be47f2SDoug Ambrisko if (error != 0) {
3322c2be47f2SDoug Ambrisko device_printf(sc->mfi_dev,
3323812819c7SDoug Ambrisko "Copy out failed\n");
3324c2be47f2SDoug Ambrisko goto out;
3325c2be47f2SDoug Ambrisko }
33265f8ad41cSAlexander Motin temp = &temp[len];
3327c2be47f2SDoug Ambrisko }
332804697de9SDoug Ambrisko }
33290d9a4ef3SDoug Ambrisko }
3330c2be47f2SDoug Ambrisko
3331812819c7SDoug Ambrisko if (ioc->mfi_sense_len) {
3332fa1e6ef4SDoug Ambrisko /* get user-space sense ptr then copy out sense */
3333dc079616SBjoern A. Zeeb bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off],
3334fa1e6ef4SDoug Ambrisko &sense_ptr.sense_ptr_data[0],
3335fa1e6ef4SDoug Ambrisko sizeof(sense_ptr.sense_ptr_data));
3336a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
3337b89b182cSDoug Ambrisko if (cmd != MFI_CMD) {
3338b89b182cSDoug Ambrisko /*
3339b89b182cSDoug Ambrisko * not 64bit native so zero out any address
3340b89b182cSDoug Ambrisko * over 32bit */
33414254ef59SDoug Ambrisko sense_ptr.addr.high = 0;
3342b89b182cSDoug Ambrisko }
3343b89b182cSDoug Ambrisko #endif
3344fa1e6ef4SDoug Ambrisko error = copyout(cm->cm_sense, sense_ptr.user_space,
3345812819c7SDoug Ambrisko ioc->mfi_sense_len);
3346c2be47f2SDoug Ambrisko if (error != 0) {
3347c2be47f2SDoug Ambrisko device_printf(sc->mfi_dev,
3348812819c7SDoug Ambrisko "Copy out failed\n");
3349c2be47f2SDoug Ambrisko goto out;
3350c2be47f2SDoug Ambrisko }
3351c2be47f2SDoug Ambrisko }
3352c2be47f2SDoug Ambrisko
3353812819c7SDoug Ambrisko ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
3354c2be47f2SDoug Ambrisko out:
33558ec5c98bSJohn Baldwin mfi_config_unlock(sc, locked);
3356c2be47f2SDoug Ambrisko if (data)
3357c2be47f2SDoug Ambrisko free(data, M_MFIBUF);
3358a6ba0fd6SDoug Ambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
3359a6ba0fd6SDoug Ambrisko for (i = 0; i < 2; i++) {
3360a6ba0fd6SDoug Ambrisko if (sc->kbuff_arr[i]) {
336127dc50b0SJohn Baldwin if (sc->mfi_kbuff_arr_busaddr[i] != 0)
3362a6ba0fd6SDoug Ambrisko bus_dmamap_unload(
3363a6ba0fd6SDoug Ambrisko sc->mfi_kbuff_arr_dmat[i],
3364a6ba0fd6SDoug Ambrisko sc->mfi_kbuff_arr_dmamap[i]
3365a6ba0fd6SDoug Ambrisko );
33660d9a4ef3SDoug Ambrisko if (sc->kbuff_arr[i] != NULL)
3367a6ba0fd6SDoug Ambrisko bus_dmamem_free(
3368a6ba0fd6SDoug Ambrisko sc->mfi_kbuff_arr_dmat[i],
3369a6ba0fd6SDoug Ambrisko sc->kbuff_arr[i],
3370a6ba0fd6SDoug Ambrisko sc->mfi_kbuff_arr_dmamap[i]
3371a6ba0fd6SDoug Ambrisko );
33720d9a4ef3SDoug Ambrisko if (sc->mfi_kbuff_arr_dmat[i] != NULL)
3373a6ba0fd6SDoug Ambrisko bus_dma_tag_destroy(
3374a6ba0fd6SDoug Ambrisko sc->mfi_kbuff_arr_dmat[i]);
33750d9a4ef3SDoug Ambrisko }
33760d9a4ef3SDoug Ambrisko }
33770d9a4ef3SDoug Ambrisko }
3378c2be47f2SDoug Ambrisko if (cm) {
3379c2be47f2SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
3380c2be47f2SDoug Ambrisko mfi_release_command(cm);
3381c2be47f2SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
3382c2be47f2SDoug Ambrisko }
3383c2be47f2SDoug Ambrisko
3384c2be47f2SDoug Ambrisko break;
3385a355f43eSDoug Ambrisko }
3386c2be47f2SDoug Ambrisko case MFI_SET_AEN:
3387c2be47f2SDoug Ambrisko aen = (struct mfi_ioc_aen *)arg;
338808c89430SSteven Hartland mtx_lock(&sc->mfi_io_lock);
3389c2be47f2SDoug Ambrisko error = mfi_aen_register(sc, aen->aen_seq_num,
3390c2be47f2SDoug Ambrisko aen->aen_class_locale);
339108c89430SSteven Hartland mtx_unlock(&sc->mfi_io_lock);
3392c2be47f2SDoug Ambrisko
3393c2be47f2SDoug Ambrisko break;
3394c2be47f2SDoug Ambrisko case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3395741367d5SDoug Ambrisko {
3396741367d5SDoug Ambrisko devclass_t devclass;
3397741367d5SDoug Ambrisko struct mfi_linux_ioc_packet l_ioc;
3398741367d5SDoug Ambrisko int adapter;
3399741367d5SDoug Ambrisko
3400741367d5SDoug Ambrisko devclass = devclass_find("mfi");
3401741367d5SDoug Ambrisko if (devclass == NULL)
3402741367d5SDoug Ambrisko return (ENOENT);
3403741367d5SDoug Ambrisko
3404741367d5SDoug Ambrisko error = copyin(arg, &l_ioc, sizeof(l_ioc));
3405741367d5SDoug Ambrisko if (error)
3406741367d5SDoug Ambrisko return (error);
3407741367d5SDoug Ambrisko adapter = l_ioc.lioc_adapter_no;
3408741367d5SDoug Ambrisko sc = devclass_get_softc(devclass, adapter);
3409741367d5SDoug Ambrisko if (sc == NULL)
3410741367d5SDoug Ambrisko return (ENOENT);
3411741367d5SDoug Ambrisko return (mfi_linux_ioctl_int(sc->mfi_cdev,
3412741367d5SDoug Ambrisko cmd, arg, flag, td));
3413741367d5SDoug Ambrisko break;
3414741367d5SDoug Ambrisko }
3415c2be47f2SDoug Ambrisko case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3416741367d5SDoug Ambrisko {
3417741367d5SDoug Ambrisko devclass_t devclass;
3418741367d5SDoug Ambrisko struct mfi_linux_ioc_aen l_aen;
3419741367d5SDoug Ambrisko int adapter;
3420741367d5SDoug Ambrisko
3421741367d5SDoug Ambrisko devclass = devclass_find("mfi");
3422741367d5SDoug Ambrisko if (devclass == NULL)
3423741367d5SDoug Ambrisko return (ENOENT);
3424741367d5SDoug Ambrisko
3425741367d5SDoug Ambrisko error = copyin(arg, &l_aen, sizeof(l_aen));
3426741367d5SDoug Ambrisko if (error)
3427741367d5SDoug Ambrisko return (error);
3428741367d5SDoug Ambrisko adapter = l_aen.laen_adapter_no;
3429741367d5SDoug Ambrisko sc = devclass_get_softc(devclass, adapter);
3430741367d5SDoug Ambrisko if (sc == NULL)
3431741367d5SDoug Ambrisko return (ENOENT);
3432741367d5SDoug Ambrisko return (mfi_linux_ioctl_int(sc->mfi_cdev,
3433741367d5SDoug Ambrisko cmd, arg, flag, td));
3434741367d5SDoug Ambrisko break;
3435741367d5SDoug Ambrisko }
3436a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
34370929b669SScott Long case MFIIO_PASSTHRU32:
3438da146236SJohn Baldwin if (!SV_CURPROC_FLAG(SV_ILP32)) {
3439da146236SJohn Baldwin error = ENOTTY;
3440da146236SJohn Baldwin break;
3441da146236SJohn Baldwin }
34420929b669SScott Long iop_swab.ioc_frame = iop32->ioc_frame;
34430929b669SScott Long iop_swab.buf_size = iop32->buf_size;
34440929b669SScott Long iop_swab.buf = PTRIN(iop32->buf);
34450929b669SScott Long iop = &iop_swab;
34460929b669SScott Long /* FALLTHROUGH */
34470929b669SScott Long #endif
34480929b669SScott Long case MFIIO_PASSTHRU:
34490929b669SScott Long error = mfi_user_command(sc, iop);
3450a6ba0fd6SDoug Ambrisko #ifdef COMPAT_FREEBSD32
34510929b669SScott Long if (cmd == MFIIO_PASSTHRU32)
34520929b669SScott Long iop32->ioc_frame = iop_swab.ioc_frame;
34530929b669SScott Long #endif
34540929b669SScott Long break;
34552e21a3efSScott Long default:
3456441f6d5dSScott Long device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3457da146236SJohn Baldwin error = ENOTTY;
34582e21a3efSScott Long break;
34592e21a3efSScott Long }
34602e21a3efSScott Long
34612e21a3efSScott Long return (error);
34622e21a3efSScott Long }
3463741367d5SDoug Ambrisko
3464741367d5SDoug Ambrisko static int
mfi_linux_ioctl_int(struct cdev * dev,u_long cmd,caddr_t arg,int flag,struct thread * td)346500b4e54aSWarner Losh mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
3466741367d5SDoug Ambrisko {
3467741367d5SDoug Ambrisko struct mfi_softc *sc;
3468741367d5SDoug Ambrisko struct mfi_linux_ioc_packet l_ioc;
3469741367d5SDoug Ambrisko struct mfi_linux_ioc_aen l_aen;
3470741367d5SDoug Ambrisko struct mfi_command *cm = NULL;
3471741367d5SDoug Ambrisko struct mfi_aen *mfi_aen_entry;
3472fa1e6ef4SDoug Ambrisko union mfi_sense_ptr sense_ptr;
34730d9a4ef3SDoug Ambrisko uint32_t context = 0;
3474741367d5SDoug Ambrisko uint8_t *data = NULL, *temp;
3475741367d5SDoug Ambrisko int i;
34768ec5c98bSJohn Baldwin int error, locked;
3477741367d5SDoug Ambrisko
3478741367d5SDoug Ambrisko sc = dev->si_drv1;
3479741367d5SDoug Ambrisko error = 0;
3480741367d5SDoug Ambrisko switch (cmd) {
3481c2be47f2SDoug Ambrisko case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
3482741367d5SDoug Ambrisko error = copyin(arg, &l_ioc, sizeof(l_ioc));
3483741367d5SDoug Ambrisko if (error != 0)
3484741367d5SDoug Ambrisko return (error);
3485741367d5SDoug Ambrisko
3486741367d5SDoug Ambrisko if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) {
3487741367d5SDoug Ambrisko return (EINVAL);
3488741367d5SDoug Ambrisko }
3489741367d5SDoug Ambrisko
3490741367d5SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
3491741367d5SDoug Ambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) {
3492741367d5SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
3493741367d5SDoug Ambrisko return (EBUSY);
3494741367d5SDoug Ambrisko }
3495741367d5SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
34968ec5c98bSJohn Baldwin locked = 0;
3497741367d5SDoug Ambrisko
3498741367d5SDoug Ambrisko /*
3499741367d5SDoug Ambrisko * save off original context since copying from user
3500741367d5SDoug Ambrisko * will clobber some data
3501741367d5SDoug Ambrisko */
3502741367d5SDoug Ambrisko context = cm->cm_frame->header.context;
3503741367d5SDoug Ambrisko
3504741367d5SDoug Ambrisko bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
350504697de9SDoug Ambrisko 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */
3506fa1e6ef4SDoug Ambrisko cm->cm_total_frame_size = (sizeof(union mfi_sgl)
3507fa1e6ef4SDoug Ambrisko * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
35080d9a4ef3SDoug Ambrisko cm->cm_frame->header.scsi_status = 0;
35090d9a4ef3SDoug Ambrisko cm->cm_frame->header.pad0 = 0;
351004697de9SDoug Ambrisko if (l_ioc.lioc_sge_count)
3511741367d5SDoug Ambrisko cm->cm_sg =
3512741367d5SDoug Ambrisko (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
351304697de9SDoug Ambrisko cm->cm_flags = 0;
351404697de9SDoug Ambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
351504697de9SDoug Ambrisko cm->cm_flags |= MFI_CMD_DATAIN;
351604697de9SDoug Ambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
351704697de9SDoug Ambrisko cm->cm_flags |= MFI_CMD_DATAOUT;
3518741367d5SDoug Ambrisko cm->cm_len = cm->cm_frame->header.data_len;
3519fa1e6ef4SDoug Ambrisko if (cm->cm_len &&
3520fa1e6ef4SDoug Ambrisko (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
3521741367d5SDoug Ambrisko cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
3522741367d5SDoug Ambrisko M_WAITOK | M_ZERO);
352304697de9SDoug Ambrisko } else {
352404697de9SDoug Ambrisko cm->cm_data = 0;
352504697de9SDoug Ambrisko }
3526741367d5SDoug Ambrisko
3527741367d5SDoug Ambrisko /* restore header context */
3528741367d5SDoug Ambrisko cm->cm_frame->header.context = context;
3529741367d5SDoug Ambrisko
3530741367d5SDoug Ambrisko temp = data;
353104697de9SDoug Ambrisko if (cm->cm_flags & MFI_CMD_DATAOUT) {
3532741367d5SDoug Ambrisko for (i = 0; i < l_ioc.lioc_sge_count; i++) {
35330929b669SScott Long error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base),
3534741367d5SDoug Ambrisko temp,
3535741367d5SDoug Ambrisko l_ioc.lioc_sgl[i].iov_len);
3536741367d5SDoug Ambrisko if (error != 0) {
3537741367d5SDoug Ambrisko device_printf(sc->mfi_dev,
3538812819c7SDoug Ambrisko "Copy in failed\n");
3539741367d5SDoug Ambrisko goto out;
3540741367d5SDoug Ambrisko }
3541741367d5SDoug Ambrisko temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3542741367d5SDoug Ambrisko }
354304697de9SDoug Ambrisko }
3544741367d5SDoug Ambrisko
35458ec5c98bSJohn Baldwin if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
35468ec5c98bSJohn Baldwin locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
35478ec5c98bSJohn Baldwin
35480a158415SDoug Ambrisko if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
3549a6ba0fd6SDoug Ambrisko cm->cm_frame->pass.sense_addr_lo =
3550a6ba0fd6SDoug Ambrisko (uint32_t)cm->cm_sense_busaddr;
3551a6ba0fd6SDoug Ambrisko cm->cm_frame->pass.sense_addr_hi =
3552a6ba0fd6SDoug Ambrisko (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
35530a158415SDoug Ambrisko }
35540a158415SDoug Ambrisko
3555441f6d5dSScott Long mtx_lock(&sc->mfi_io_lock);
35568ec5c98bSJohn Baldwin error = mfi_check_command_pre(sc, cm);
35578ec5c98bSJohn Baldwin if (error) {
35588ec5c98bSJohn Baldwin mtx_unlock(&sc->mfi_io_lock);
35598ec5c98bSJohn Baldwin goto out;
35608ec5c98bSJohn Baldwin }
35618ec5c98bSJohn Baldwin
35625be25877SDoug Ambrisko if ((error = mfi_wait_command(sc, cm)) != 0) {
3563741367d5SDoug Ambrisko device_printf(sc->mfi_dev,
3564812819c7SDoug Ambrisko "Controller polled failed\n");
3565441f6d5dSScott Long mtx_unlock(&sc->mfi_io_lock);
3566741367d5SDoug Ambrisko goto out;
3567741367d5SDoug Ambrisko }
3568741367d5SDoug Ambrisko
35698ec5c98bSJohn Baldwin mfi_check_command_post(sc, cm);
3570441f6d5dSScott Long mtx_unlock(&sc->mfi_io_lock);
3571741367d5SDoug Ambrisko
3572741367d5SDoug Ambrisko temp = data;
357304697de9SDoug Ambrisko if (cm->cm_flags & MFI_CMD_DATAIN) {
3574741367d5SDoug Ambrisko for (i = 0; i < l_ioc.lioc_sge_count; i++) {
3575741367d5SDoug Ambrisko error = copyout(temp,
35760929b669SScott Long PTRIN(l_ioc.lioc_sgl[i].iov_base),
3577741367d5SDoug Ambrisko l_ioc.lioc_sgl[i].iov_len);
3578741367d5SDoug Ambrisko if (error != 0) {
3579741367d5SDoug Ambrisko device_printf(sc->mfi_dev,
3580812819c7SDoug Ambrisko "Copy out failed\n");
3581741367d5SDoug Ambrisko goto out;
3582741367d5SDoug Ambrisko }
3583741367d5SDoug Ambrisko temp = &temp[l_ioc.lioc_sgl[i].iov_len];
3584741367d5SDoug Ambrisko }
358504697de9SDoug Ambrisko }
3586741367d5SDoug Ambrisko
3587741367d5SDoug Ambrisko if (l_ioc.lioc_sense_len) {
3588fa1e6ef4SDoug Ambrisko /* get user-space sense ptr then copy out sense */
3589fa1e6ef4SDoug Ambrisko bcopy(&((struct mfi_linux_ioc_packet*)arg)
3590fa1e6ef4SDoug Ambrisko ->lioc_frame.raw[l_ioc.lioc_sense_off],
3591fa1e6ef4SDoug Ambrisko &sense_ptr.sense_ptr_data[0],
3592fa1e6ef4SDoug Ambrisko sizeof(sense_ptr.sense_ptr_data));
3593b89b182cSDoug Ambrisko #ifdef __amd64__
3594b89b182cSDoug Ambrisko /*
3595b89b182cSDoug Ambrisko * only 32bit Linux support so zero out any
3596b89b182cSDoug Ambrisko * address over 32bit
3597b89b182cSDoug Ambrisko */
35984254ef59SDoug Ambrisko sense_ptr.addr.high = 0;
3599b89b182cSDoug Ambrisko #endif
3600fa1e6ef4SDoug Ambrisko error = copyout(cm->cm_sense, sense_ptr.user_space,
3601741367d5SDoug Ambrisko l_ioc.lioc_sense_len);
3602741367d5SDoug Ambrisko if (error != 0) {
3603741367d5SDoug Ambrisko device_printf(sc->mfi_dev,
3604812819c7SDoug Ambrisko "Copy out failed\n");
3605741367d5SDoug Ambrisko goto out;
3606741367d5SDoug Ambrisko }
3607741367d5SDoug Ambrisko }
3608741367d5SDoug Ambrisko
3609741367d5SDoug Ambrisko error = copyout(&cm->cm_frame->header.cmd_status,
3610741367d5SDoug Ambrisko &((struct mfi_linux_ioc_packet*)arg)
3611741367d5SDoug Ambrisko ->lioc_frame.hdr.cmd_status,
3612741367d5SDoug Ambrisko 1);
3613741367d5SDoug Ambrisko if (error != 0) {
3614741367d5SDoug Ambrisko device_printf(sc->mfi_dev,
3615812819c7SDoug Ambrisko "Copy out failed\n");
3616741367d5SDoug Ambrisko goto out;
3617741367d5SDoug Ambrisko }
3618741367d5SDoug Ambrisko
3619741367d5SDoug Ambrisko out:
36208ec5c98bSJohn Baldwin mfi_config_unlock(sc, locked);
3621741367d5SDoug Ambrisko if (data)
3622741367d5SDoug Ambrisko free(data, M_MFIBUF);
3623741367d5SDoug Ambrisko if (cm) {
3624741367d5SDoug Ambrisko mtx_lock(&sc->mfi_io_lock);
3625741367d5SDoug Ambrisko mfi_release_command(cm);
3626741367d5SDoug Ambrisko mtx_unlock(&sc->mfi_io_lock);
3627741367d5SDoug Ambrisko }
3628741367d5SDoug Ambrisko
3629741367d5SDoug Ambrisko return (error);
3630c2be47f2SDoug Ambrisko case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
3631741367d5SDoug Ambrisko error = copyin(arg, &l_aen, sizeof(l_aen));
3632741367d5SDoug Ambrisko if (error != 0)
3633741367d5SDoug Ambrisko return (error);
3634741367d5SDoug Ambrisko printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid);
3635741367d5SDoug Ambrisko mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF,
3636741367d5SDoug Ambrisko M_WAITOK);
3637441f6d5dSScott Long mtx_lock(&sc->mfi_io_lock);
3638741367d5SDoug Ambrisko mfi_aen_entry->p = curproc;
3639701308efSZhenlei Huang TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry, aen_link);
3640741367d5SDoug Ambrisko error = mfi_aen_register(sc, l_aen.laen_seq_num,
3641741367d5SDoug Ambrisko l_aen.laen_class_locale);
3642741367d5SDoug Ambrisko
3643741367d5SDoug Ambrisko if (error != 0) {
3644741367d5SDoug Ambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
3645741367d5SDoug Ambrisko aen_link);
3646741367d5SDoug Ambrisko free(mfi_aen_entry, M_MFIBUF);
3647741367d5SDoug Ambrisko }
3648441f6d5dSScott Long mtx_unlock(&sc->mfi_io_lock);
3649741367d5SDoug Ambrisko
3650741367d5SDoug Ambrisko return (error);
3651741367d5SDoug Ambrisko default:
3652741367d5SDoug Ambrisko device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd);
3653741367d5SDoug Ambrisko error = ENOENT;
3654741367d5SDoug Ambrisko break;
3655741367d5SDoug Ambrisko }
3656741367d5SDoug Ambrisko
3657741367d5SDoug Ambrisko return (error);
3658741367d5SDoug Ambrisko }
3659741367d5SDoug Ambrisko
3660741367d5SDoug Ambrisko static int
mfi_poll(struct cdev * dev,int poll_events,struct thread * td)3661741367d5SDoug Ambrisko mfi_poll(struct cdev *dev, int poll_events, struct thread *td)
3662741367d5SDoug Ambrisko {
3663741367d5SDoug Ambrisko struct mfi_softc *sc;
3664741367d5SDoug Ambrisko int revents = 0;
3665741367d5SDoug Ambrisko
3666741367d5SDoug Ambrisko sc = dev->si_drv1;
3667741367d5SDoug Ambrisko
3668741367d5SDoug Ambrisko if (poll_events & (POLLIN | POLLRDNORM)) {
3669441f6d5dSScott Long if (sc->mfi_aen_triggered != 0) {
3670741367d5SDoug Ambrisko revents |= poll_events & (POLLIN | POLLRDNORM);
3671441f6d5dSScott Long sc->mfi_aen_triggered = 0;
3672441f6d5dSScott Long }
3673741367d5SDoug Ambrisko if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) {
3674741367d5SDoug Ambrisko revents |= POLLERR;
3675741367d5SDoug Ambrisko }
3676741367d5SDoug Ambrisko }
3677741367d5SDoug Ambrisko
3678741367d5SDoug Ambrisko if (revents == 0) {
3679741367d5SDoug Ambrisko if (poll_events & (POLLIN | POLLRDNORM)) {
3680741367d5SDoug Ambrisko sc->mfi_poll_waiting = 1;
3681741367d5SDoug Ambrisko selrecord(td, &sc->mfi_select);
3682741367d5SDoug Ambrisko }
3683741367d5SDoug Ambrisko }
3684741367d5SDoug Ambrisko
3685741367d5SDoug Ambrisko return revents;
3686741367d5SDoug Ambrisko }
36875ba21ff1SScott Long
3688441f6d5dSScott Long static void
mfi_dump_all(void)3689441f6d5dSScott Long mfi_dump_all(void)
3690441f6d5dSScott Long {
3691441f6d5dSScott Long struct mfi_softc *sc;
3692441f6d5dSScott Long struct mfi_command *cm;
3693441f6d5dSScott Long devclass_t dc;
3694441f6d5dSScott Long time_t deadline;
36953dbe05f6SDimitry Andric int timedout __unused;
3696441f6d5dSScott Long int i;
3697441f6d5dSScott Long
3698441f6d5dSScott Long dc = devclass_find("mfi");
3699441f6d5dSScott Long if (dc == NULL) {
3700441f6d5dSScott Long printf("No mfi dev class\n");
3701441f6d5dSScott Long return;
3702441f6d5dSScott Long }
3703441f6d5dSScott Long
3704441f6d5dSScott Long for (i = 0; ; i++) {
3705441f6d5dSScott Long sc = devclass_get_softc(dc, i);
3706441f6d5dSScott Long if (sc == NULL)
3707441f6d5dSScott Long break;
3708441f6d5dSScott Long device_printf(sc->mfi_dev, "Dumping\n\n");
3709441f6d5dSScott Long timedout = 0;
3710f108bdaaSSteven Hartland deadline = time_uptime - mfi_cmd_timeout;
37115ba21ff1SScott Long mtx_lock(&sc->mfi_io_lock);
37125ba21ff1SScott Long TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
371308c89430SSteven Hartland if (cm->cm_timestamp <= deadline) {
37145ba21ff1SScott Long device_printf(sc->mfi_dev,
3715a6ba0fd6SDoug Ambrisko "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3716a6ba0fd6SDoug Ambrisko cm, (int)(time_uptime - cm->cm_timestamp));
37175ba21ff1SScott Long MFI_PRINT_CMD(cm);
37185ba21ff1SScott Long timedout++;
37195ba21ff1SScott Long }
37205ba21ff1SScott Long }
37215ba21ff1SScott Long
37225ba21ff1SScott Long #if 0
37235ba21ff1SScott Long if (timedout)
372408c89430SSteven Hartland MFI_DUMP_CMDS(sc);
37255ba21ff1SScott Long #endif
37265ba21ff1SScott Long
37275ba21ff1SScott Long mtx_unlock(&sc->mfi_io_lock);
3728441f6d5dSScott Long }
3729441f6d5dSScott Long
3730441f6d5dSScott Long return;
3731441f6d5dSScott Long }
3732441f6d5dSScott Long
3733441f6d5dSScott Long static void
mfi_timeout(void * data)3734441f6d5dSScott Long mfi_timeout(void *data)
3735441f6d5dSScott Long {
3736441f6d5dSScott Long struct mfi_softc *sc = (struct mfi_softc *)data;
373708c89430SSteven Hartland struct mfi_command *cm, *tmp;
3738441f6d5dSScott Long time_t deadline;
37393dbe05f6SDimitry Andric int timedout __unused = 0;
3740441f6d5dSScott Long
3741f108bdaaSSteven Hartland deadline = time_uptime - mfi_cmd_timeout;
3742a6ba0fd6SDoug Ambrisko if (sc->adpreset == 0) {
3743a6ba0fd6SDoug Ambrisko if (!mfi_tbolt_reset(sc)) {
3744f108bdaaSSteven Hartland callout_reset(&sc->mfi_watchdog_callout,
3745f108bdaaSSteven Hartland mfi_cmd_timeout * hz, mfi_timeout, sc);
37460d9a4ef3SDoug Ambrisko return;
37470d9a4ef3SDoug Ambrisko }
37480d9a4ef3SDoug Ambrisko }
3749441f6d5dSScott Long mtx_lock(&sc->mfi_io_lock);
375008c89430SSteven Hartland TAILQ_FOREACH_SAFE(cm, &sc->mfi_busy, cm_link, tmp) {
3751ddbffe7fSDoug Ambrisko if (sc->mfi_aen_cm == cm || sc->mfi_map_sync_cm == cm)
3752441f6d5dSScott Long continue;
375308c89430SSteven Hartland if (cm->cm_timestamp <= deadline) {
37540d9a4ef3SDoug Ambrisko if (sc->adpreset != 0 && sc->issuepend_done == 0) {
37550d9a4ef3SDoug Ambrisko cm->cm_timestamp = time_uptime;
3756a6ba0fd6SDoug Ambrisko } else {
3757441f6d5dSScott Long device_printf(sc->mfi_dev,
3758a6ba0fd6SDoug Ambrisko "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
3759a6ba0fd6SDoug Ambrisko cm, (int)(time_uptime - cm->cm_timestamp)
3760a6ba0fd6SDoug Ambrisko );
3761441f6d5dSScott Long MFI_PRINT_CMD(cm);
3762441f6d5dSScott Long MFI_VALIDATE_CMD(sc, cm);
376308c89430SSteven Hartland /*
37645dd4da9fSSteven Hartland * While commands can get stuck forever we do
37655dd4da9fSSteven Hartland * not fail them as there is no way to tell if
37665dd4da9fSSteven Hartland * the controller has actually processed them
37675dd4da9fSSteven Hartland * or not.
37685dd4da9fSSteven Hartland *
37695dd4da9fSSteven Hartland * In addition its very likely that force
37705dd4da9fSSteven Hartland * failing a command here would cause a panic
37715dd4da9fSSteven Hartland * e.g. in UFS.
377208c89430SSteven Hartland */
3773441f6d5dSScott Long timedout++;
3774441f6d5dSScott Long }
3775441f6d5dSScott Long }
37760d9a4ef3SDoug Ambrisko }
3777441f6d5dSScott Long
3778441f6d5dSScott Long #if 0
3779441f6d5dSScott Long if (timedout)
378008c89430SSteven Hartland MFI_DUMP_CMDS(sc);
3781441f6d5dSScott Long #endif
3782441f6d5dSScott Long
3783441f6d5dSScott Long mtx_unlock(&sc->mfi_io_lock);
37845ba21ff1SScott Long
3785f108bdaaSSteven Hartland callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz,
37865ba21ff1SScott Long mfi_timeout, sc);
37875ba21ff1SScott Long
3788441f6d5dSScott Long if (0)
3789441f6d5dSScott Long mfi_dump_all();
37905ba21ff1SScott Long return;
37915ba21ff1SScott Long }
3792