From 590ba11dd1b31a5cbd5ae62f96ba8eea413eceee Mon Sep 17 00:00:00 2001 From: Sascha Wildner Date: Thu, 29 Mar 2012 20:05:12 +0200 Subject: [PATCH] mfi(4): Update to LSI's version 4.23 of the driver. Brings in support for newer SAS2208 (aka Thunderbolt) based controllers. It was tested with an Intel RS25DB080. A few other things have been fixed too. Most x86_64/i386 specific parts have been merged, MSI is now setup in mfi_pci.c properly. Taken-from: FreeBSD (from their projects/ repository) --- share/man/man4/mfi.4 | 22 +- sys/conf/files | 1 + sys/dev/raid/mfi/Makefile | 2 +- sys/dev/raid/mfi/mfi.c | 1204 +++++++++++++++++++----------- sys/dev/raid/mfi/mfi_cam.c | 36 +- sys/dev/raid/mfi/mfi_debug.c | 21 +- sys/dev/raid/mfi/mfi_disk.c | 44 +- sys/dev/raid/mfi/mfi_ioctl.h | 42 +- sys/dev/raid/mfi/mfi_pci.c | 88 +-- sys/dev/raid/mfi/mfi_syspd.c | 41 +- sys/dev/raid/mfi/mfi_tbolt.c | 1342 ++++++++++++++++++++++++++++++++++ sys/dev/raid/mfi/mfireg.h | 643 ++++++++++++++-- sys/dev/raid/mfi/mfivar.h | 218 ++++-- 13 files changed, 3014 insertions(+), 690 deletions(-) create mode 100644 sys/dev/raid/mfi/mfi_tbolt.c diff --git a/share/man/man4/mfi.4 b/share/man/man4/mfi.4 index ffad85e590..54979a8865 100644 --- a/share/man/man4/mfi.4 +++ b/share/man/man4/mfi.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD: src/share/man/man4/mfi.4,v 1.13 2010/05/12 17:12:38 brueffer Exp $ .\" -.Dd August 11, 2011 +.Dd March 24, 2012 .Dt MFI 4 .Os .Sh NAME @@ -127,6 +127,22 @@ Dell PERC5 .It Dell PERC6 .It +Dell PERC H710 Embedded +.It +Dell PERC H710 Adapter +.It +Dell PERC H710 Mini (blades) +.It +Dell PERC H710 Mini (monolithics) +.It +Dell PERC H710P Adapter +.It +Dell PERC H710P Mini (blades) +.It +Dell PERC H710P Mini (monolithics) +.It +Dell PERC H810 Adapter +.It IBM ServeRAID M1015 SAS/SATA .It IBM ServeRAID M5015 SAS/SATA @@ -134,6 +150,10 @@ IBM ServeRAID M5015 SAS/SATA IBM ServeRAID-MR10i .It Intel RAID Controller SROMBSAS18E +.It +Intel RAID Controller RS25DB080 +.It +Intel RAID Controller RS25NB008 .El .Sh FILES .Bl -tag -width ".Pa /dev/mfisyspd?" -compact diff --git a/sys/conf/files b/sys/conf/files index e9f24743af..ceff74676e 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -578,6 +578,7 @@ dev/raid/mfi/mfi_debug.c optional mfi dev/raid/mfi/mfi_pci.c optional mfi pci dev/raid/mfi/mfi_disk.c optional mfi dev/raid/mfi/mfi_syspd.c optional mfi +dev/raid/mfi/mfi_tbolt.c optional mfi dev/raid/mfi/mfi_linux.c optional mfi compat_linux dev/raid/mfi/mfi_cam.c optional mfip scbus dev/netif/mii_layer/mii.c optional miibus diff --git a/sys/dev/raid/mfi/Makefile b/sys/dev/raid/mfi/Makefile index 809eac3af3..62557da25a 100644 --- a/sys/dev/raid/mfi/Makefile +++ b/sys/dev/raid/mfi/Makefile @@ -8,7 +8,7 @@ SUBDIR+= mfi_linux .endif KMOD= mfi -SRCS= mfi.c mfi_pci.c mfi_disk.c mfi_debug.c mfi_syspd.c +SRCS= mfi.c mfi_pci.c mfi_disk.c mfi_debug.c mfi_syspd.c mfi_tbolt.c SRCS+= opt_mfi.h opt_cam.h SRCS+= device_if.h bus_if.h pci_if.h diff --git a/sys/dev/raid/mfi/mfi.c b/sys/dev/raid/mfi/mfi.c index 843f6d77ce..ad3bbaadd3 100644 --- a/sys/dev/raid/mfi/mfi.c +++ b/sys/dev/raid/mfi/mfi.c @@ -48,38 +48,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - */ -/*- - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Copyright 1994-2009 The FreeBSD Project. - * All rights reserved. - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfi.c,v 1.62 2011/11/09 21:53:49 delphij Exp $ + * FreeBSD projects/head_mfi/ r233016 */ #include "opt_mfi.h" @@ -99,6 +70,7 @@ #include #include #include +#include #include @@ -110,7 +82,6 @@ static int mfi_alloc_commands(struct mfi_softc *); static int mfi_comms_init(struct mfi_softc *); -static int mfi_wait_command(struct mfi_softc *, struct mfi_command *); static int mfi_get_controller_info(struct mfi_softc *); static int mfi_get_log_state(struct mfi_softc *, struct mfi_evt_log_state **); @@ -122,33 +93,39 @@ static void mfi_startup(void *arg); static void mfi_intr(void *arg); static void mfi_ldprobe(struct mfi_softc *sc); static void mfi_syspdprobe(struct mfi_softc *sc); +static void mfi_handle_evt(void *context, int pending); static int mfi_aen_register(struct mfi_softc *sc, int seq, int locale); static void mfi_aen_complete(struct mfi_command *); -static int mfi_aen_setup(struct mfi_softc *, uint32_t); static int mfi_add_ld(struct mfi_softc *sc, int); static void mfi_add_ld_complete(struct mfi_command *); static int mfi_add_sys_pd(struct mfi_softc *sc, int); static void mfi_add_sys_pd_complete(struct mfi_command *); -static struct mfi_command * mfi_bio_command(struct mfi_softc *); +static struct mfi_command *mfi_bio_command(struct mfi_softc *); static void mfi_bio_complete(struct mfi_command *); -static struct mfi_command * mfi_build_ldio(struct mfi_softc *,struct bio*); -static struct mfi_command * mfi_build_syspdio(struct mfi_softc *,struct bio*); -static int mfi_mapcmd(struct mfi_softc *, struct mfi_command *); +static struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*); +static struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*); static int mfi_send_frame(struct mfi_softc *, struct mfi_command *); -static void mfi_complete(struct mfi_softc *, struct mfi_command *); static int mfi_abort(struct mfi_softc *, struct mfi_command *); static int mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int); static void mfi_timeout(void *); static int mfi_user_command(struct mfi_softc *, struct mfi_ioc_passthru *); -static void mfi_enable_intr_xscale(struct mfi_softc *sc); -static void mfi_enable_intr_ppc(struct mfi_softc *sc); -static int32_t mfi_read_fw_status_xscale(struct mfi_softc *sc); -static int32_t mfi_read_fw_status_ppc(struct mfi_softc *sc); -static int mfi_check_clear_intr_xscale(struct mfi_softc *sc); -static int mfi_check_clear_intr_ppc(struct mfi_softc *sc); -static void mfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt); -static void mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt); +static void mfi_enable_intr_xscale(struct mfi_softc *sc); +static void mfi_enable_intr_ppc(struct mfi_softc *sc); +static int32_t mfi_read_fw_status_xscale(struct mfi_softc *sc); +static int32_t mfi_read_fw_status_ppc(struct mfi_softc *sc); +static int mfi_check_clear_intr_xscale(struct mfi_softc *sc); +static int mfi_check_clear_intr_ppc(struct mfi_softc *sc); +static void mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, + uint32_t frame_cnt); +static void mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, + uint32_t frame_cnt); +static int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode); +static void mfi_config_unlock(struct mfi_softc *sc, int locked); +static int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm); +static void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm); +static int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm); + static void mfi_filter_detach(struct knote *); static int mfi_filter_read(struct knote *, long); static int mfi_filter_write(struct knote *, long); @@ -169,8 +146,10 @@ TUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds); SYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RD, &mfi_max_cmds, 0, "Max commands"); -static int mfi_msi_enable = 1; -TUNABLE_INT("hw.mfi.msi.enable", &mfi_msi_enable); +static int mfi_detect_jbod_change = 1; +TUNABLE_INT("hw.mfi.detect_jbod_change", &mfi_detect_jbod_change); +SYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RW, + &mfi_detect_jbod_change, 0, "Detect a change to a JBOD"); /* Management interface */ static d_open_t mfi_open; @@ -180,7 +159,7 @@ static d_kqfilter_t mfi_kqfilter; static struct dev_ops mfi_ops = { { "mfi", 0, 0 }, - .d_open = mfi_open, + .d_open = mfi_open, .d_close = mfi_close, .d_ioctl = mfi_ioctl, .d_kqfilter = mfi_kqfilter, @@ -194,6 +173,7 @@ static struct filterops mfi_write_filterops = MALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver"); #define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH +struct mfi_skinny_dma_info mfi_skinny; static void mfi_enable_intr_xscale(struct mfi_softc *sc) @@ -261,13 +241,13 @@ mfi_check_clear_intr_ppc(struct mfi_softc *sc) } static void -mfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt) +mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt) { MFI_WRITE4(sc, MFI_IQP,(bus_add >>3) | frame_cnt); } static void -mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt) +mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt) { if (sc->mfi_flags & MFI_FLAGS_SKINNY) { MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt << 1) | 1); @@ -277,18 +257,16 @@ mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt) } } -static int +int mfi_transition_firmware(struct mfi_softc *sc) { uint32_t fw_state, cur_state; int max_wait, i; uint32_t cur_abs_reg_val = 0; uint32_t prev_abs_reg_val = 0; - bus_space_handle_t idb; cur_abs_reg_val = sc->mfi_read_fw_status(sc); fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK; - idb = sc->mfi_flags & MFI_FLAGS_SKINNY ? MFI_SKINNY_IDB : MFI_IDB; while (fw_state != MFI_FWSTATE_READY) { if (bootverbose) device_printf(sc->mfi_dev, "Waiting for firmware to " @@ -299,31 +277,43 @@ mfi_transition_firmware(struct mfi_softc *sc) device_printf(sc->mfi_dev, "Firmware fault\n"); return (ENXIO); case MFI_FWSTATE_WAIT_HANDSHAKE: - MFI_WRITE4(sc, idb, MFI_FWINIT_CLEAR_HANDSHAKE); - max_wait = 2; + if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) + MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE); + else + MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE); + max_wait = MFI_RESET_WAIT_TIME; break; case MFI_FWSTATE_OPERATIONAL: - MFI_WRITE4(sc, idb, MFI_FWINIT_READY); - max_wait = 10; + if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) + MFI_WRITE4(sc, MFI_SKINNY_IDB, 7); + else + MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY); + max_wait = MFI_RESET_WAIT_TIME; break; case MFI_FWSTATE_UNDEFINED: case MFI_FWSTATE_BB_INIT: - max_wait = 2; + max_wait = MFI_RESET_WAIT_TIME; + break; + case MFI_FWSTATE_FW_INIT_2: + max_wait = MFI_RESET_WAIT_TIME; break; case MFI_FWSTATE_FW_INIT: case MFI_FWSTATE_FLUSH_CACHE: - max_wait = 20; + max_wait = MFI_RESET_WAIT_TIME; break; case MFI_FWSTATE_DEVICE_SCAN: - max_wait = 180; /* wait for 180 seconds */ + max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */ prev_abs_reg_val = cur_abs_reg_val; break; case MFI_FWSTATE_BOOT_MESSAGE_PENDING: - MFI_WRITE4(sc, idb, MFI_FWINIT_HOTPLUG); - max_wait = 10; + if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) + MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG); + else + MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG); + max_wait = MFI_RESET_WAIT_TIME; break; default: - device_printf(sc->mfi_dev,"Unknown firmware state %#x\n", + device_printf(sc->mfi_dev, "Unknown firmware state %#x\n", fw_state); return (ENXIO); } @@ -349,25 +339,14 @@ mfi_transition_firmware(struct mfi_softc *sc) return (0); } -#if defined(__x86_64__) static void -mfi_addr64_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +mfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { - uint64_t *addr; + bus_addr_t *addr; addr = arg; *addr = segs[0].ds_addr; } -#else -static void -mfi_addr32_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) -{ - uint32_t *addr; - - addr = arg; - *addr = segs[0].ds_addr; -} -#endif int mfi_attach(struct mfi_softc *sc) @@ -375,14 +354,20 @@ mfi_attach(struct mfi_softc *sc) uint32_t status; int error, commsz, framessz, sensesz; int frames, unit, max_fw_sge; - u_int irq_flags; + uint32_t tb_mem_size = 0; - device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 3.981\n"); + if (sc == NULL) + return EINVAL; + + device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n", + MEGASAS_VERSION); lockinit(&sc->mfi_io_lock, "MFI I/O lock", 0, LK_CANRECURSE); lockinit(&sc->mfi_config_lock, "MFI config", 0, LK_CANRECURSE); TAILQ_INIT(&sc->mfi_ld_tqh); TAILQ_INIT(&sc->mfi_syspd_tqh); + TAILQ_INIT(&sc->mfi_evt_queue); + TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc); TAILQ_INIT(&sc->mfi_aen_pids); TAILQ_INIT(&sc->mfi_cam_ccbq); @@ -391,11 +376,26 @@ mfi_attach(struct mfi_softc *sc) mfi_initq_busy(sc); mfi_initq_bio(sc); + sc->adpreset = 0; + sc->last_seq_num = 0; + sc->disableOnlineCtrlReset = 1; + sc->issuepend_done = 1; + sc->hw_crit_error = 0; + if (sc->mfi_flags & MFI_FLAGS_1064R) { sc->mfi_enable_intr = mfi_enable_intr_xscale; sc->mfi_read_fw_status = mfi_read_fw_status_xscale; sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale; sc->mfi_issue_cmd = mfi_issue_cmd_xscale; + } else if (sc->mfi_flags & MFI_FLAGS_TBOLT) { + sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc; + sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc; + sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc; + sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc; + sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc; + sc->mfi_adp_reset = mfi_tbolt_adp_reset; + sc->mfi_tbolt = 1; + TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh); } else { sc->mfi_enable_intr = mfi_enable_intr_ppc; sc->mfi_read_fw_status = mfi_read_fw_status_ppc; @@ -411,6 +411,31 @@ mfi_attach(struct mfi_softc *sc) return (ENXIO); } + /* Start: LSIP200113393 */ + if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsize */ + 1, /* msegments */ + MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsegsize */ + 0, /* flags */ + &sc->verbuf_h_dmat)) { + device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf, + BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) { + device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n"); + return (ENOMEM); + } + bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t)); + bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap, + sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t), + mfi_addr_cb, &sc->verbuf_h_busaddr, 0); + /* End: LSIP200113393 */ + /* * Get information needed for sizing the contiguous memory for the * frame pool. Size down the sgl parameter since we know that @@ -423,6 +448,97 @@ mfi_attach(struct mfi_softc *sc) max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16; sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1)); + /* ThunderBolt Support get the contiguous memory */ + + if (sc->mfi_flags & MFI_FLAGS_TBOLT) { + mfi_tbolt_init_globals(sc); + device_printf(sc->mfi_dev, "MaxCmd = %x MaxSgl = %x state = %x \n", + sc->mfi_max_fw_cmds, sc->mfi_max_sge, status); + tb_mem_size = mfi_tbolt_get_memory_requirement(sc); + + if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + tb_mem_size, /* maxsize */ + 1, /* msegments */ + tb_mem_size, /* maxsegsize */ + 0, /* flags */ + &sc->mfi_tb_dmat)) { + device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool, + BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) { + device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); + return (ENOMEM); + } + bzero(sc->request_message_pool, tb_mem_size); + bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap, + sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0); + + /* For ThunderBolt memory init */ + if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ + 0x100, 0, /* alignmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MFI_FRAME_SIZE, /* maxsize */ + 1, /* msegments */ + MFI_FRAME_SIZE, /* maxsegsize */ + 0, /* flags */ + &sc->mfi_tb_init_dmat)) { + device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init, + BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) { + device_printf(sc->mfi_dev, "Cannot allocate init memory\n"); + return (ENOMEM); + } + bzero(sc->mfi_tb_init, MFI_FRAME_SIZE); + bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap, + sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb, + &sc->mfi_tb_init_busaddr, 0); + if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool, + tb_mem_size)) { + device_printf(sc->mfi_dev, + "Thunderbolt pool preparation error\n"); + return 0; + } + + /* + Allocate DMA memory mapping for MPI2 IOC Init descriptor, + we are taking it diffrent from what we have allocated for Request + and reply descriptors to avoid confusion later + */ + tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST); + if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + tb_mem_size, /* maxsize */ + 1, /* msegments */ + tb_mem_size, /* maxsegsize */ + 0, /* flags */ + &sc->mfi_tb_ioc_init_dmat)) { + device_printf(sc->mfi_dev, + "Cannot allocate comms DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat, + (void **)&sc->mfi_tb_ioc_init_desc, + BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) { + device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); + return (ENOMEM); + } + bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size); + bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap, + sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb, + &sc->mfi_tb_ioc_init_busaddr, 0); + } /* * Create the dma tag for data buffers. Used both for block I/O * and for various internal data queries. @@ -468,14 +584,8 @@ mfi_attach(struct mfi_softc *sc) return (ENOMEM); } bzero(sc->mfi_comms, commsz); -#if defined(__x86_64__) - bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap, - sc->mfi_comms, commsz, mfi_addr64_cb, &sc->mfi_comms_busaddr, 0); -#else bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap, - sc->mfi_comms, commsz, mfi_addr32_cb, &sc->mfi_comms_busaddr, 0); -#endif - + sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0); /* * Allocate DMA memory for the command frames. Keep them in the * lower 4GB for efficiency. Calculate the size of the commands at @@ -516,14 +626,8 @@ mfi_attach(struct mfi_softc *sc) return (ENOMEM); } bzero(sc->mfi_frames, framessz); -#if defined(__x86_64__) - bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap, - sc->mfi_frames, framessz, mfi_addr64_cb, &sc->mfi_frames_busaddr,0); -#else bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap, - sc->mfi_frames, framessz, mfi_addr32_cb, &sc->mfi_frames_busaddr,0); -#endif - + sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0); /* * Allocate DMA memory for the frame sense data. Keep them in the * lower 4GB for efficiency @@ -547,47 +651,48 @@ mfi_attach(struct mfi_softc *sc) device_printf(sc->mfi_dev, "Cannot allocate sense memory\n"); return (ENOMEM); } -#if defined(__x86_64__) bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap, - sc->mfi_sense, sensesz, mfi_addr64_cb, &sc->mfi_sense_busaddr, 0); -#else - bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap, - sc->mfi_sense, sensesz, mfi_addr32_cb, &sc->mfi_sense_busaddr, 0); -#endif - + sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0); if ((error = mfi_alloc_commands(sc)) != 0) return (error); - if ((error = mfi_comms_init(sc)) != 0) - return (error); + /* + * Before moving the FW to operational state, check whether + * hostmemory is required by the FW or not + */ - if ((error = mfi_get_controller_info(sc)) != 0) - return (error); + /* ThunderBolt MFI_IOC2 INIT */ + if (sc->mfi_flags & MFI_FLAGS_TBOLT) { + sc->mfi_disable_intr(sc); + if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) { + device_printf(sc->mfi_dev, + "TB Init has failed with error %d\n",error); + return error; + } - lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); - if ((error = mfi_aen_setup(sc, 0), 0) != 0) { - lockmgr(&sc->mfi_io_lock, LK_RELEASE); - return (error); - } - lockmgr(&sc->mfi_io_lock, LK_RELEASE); + if ((error = mfi_tbolt_alloc_cmd(sc)) != 0) + return error; + if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE, + mfi_intr_tbolt, sc, &sc->mfi_intr, NULL)) { + device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); + return (EINVAL); + } + sc->mfi_enable_intr(sc); + sc->map_id = 0; + } else { + if ((error = mfi_comms_init(sc)) != 0) + return (error); - /* - * Set up the interrupt handler. XXX This should happen in - * mfi_pci.c - */ - sc->mfi_irq_rid = 0; - sc->mfi_irq_type = pci_alloc_1intr(sc->mfi_dev, mfi_msi_enable, - &sc->mfi_irq_rid, &irq_flags); - if ((sc->mfi_irq = bus_alloc_resource_any(sc->mfi_dev, SYS_RES_IRQ, - &sc->mfi_irq_rid, irq_flags)) == NULL) { - device_printf(sc->mfi_dev, "Cannot allocate interrupt\n"); - return (EINVAL); - } - if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE, - mfi_intr, sc, &sc->mfi_intr, NULL)) { - device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); - return (EINVAL); + if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE, + mfi_intr, sc, &sc->mfi_intr, NULL)) { + device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); + return (EINVAL); + } + sc->mfi_enable_intr(sc); } + if ((error = mfi_get_controller_info(sc)) != 0) + return (error); + sc->disableOnlineCtrlReset = 0; /* Register a config hook to probe the bus for arrays */ sc->mfi_ich.ich_func = mfi_startup; @@ -597,6 +702,10 @@ mfi_attach(struct mfi_softc *sc) "hook\n"); return (EINVAL); } + if ((error = mfi_aen_setup(sc, 0), 0) != 0) { + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + return (error); + } /* * Register a shutdown handler. @@ -676,8 +785,11 @@ mfi_alloc_commands(struct mfi_softc *sc) cm->cm_sc = sc; cm->cm_index = i; if (bus_dmamap_create(sc->mfi_buffer_dmat, 0, - &cm->cm_dmamap) == 0) + &cm->cm_dmamap) == 0) { + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); mfi_release_command(cm); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + } else break; sc->mfi_total_cmds++; @@ -692,6 +804,8 @@ mfi_release_command(struct mfi_command *cm) struct mfi_frame_header *hdr; uint32_t *hdr_data; + KKASSERT(lockstatus(&cm->cm_sc->mfi_io_lock, curthread) != 0); + /* * Zero out the important fields of the frame, but make sure the * context field is preserved. For efficiency, handle the fields @@ -716,13 +830,14 @@ mfi_release_command(struct mfi_command *cm) cm->cm_data = NULL; cm->cm_sg = 0; cm->cm_total_frame_size = 0; + cm->retry_for_fw_reset = 0; mfi_enqueue_free(cm); } static int -mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode, - void **bufp, size_t bufsize) +mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, + uint32_t opcode, void **bufp, size_t bufsize) { struct mfi_command *cm; struct mfi_dcmd_frame *dcmd; @@ -852,9 +967,11 @@ mfi_get_controller_info(struct mfi_softc *sc) BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); - max_sectors_1 = (1 << ci->stripe_sz_ops.min) * ci->max_strips_per_io; + max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io; max_sectors_2 = ci->max_request_size; sc->mfi_max_io = min(max_sectors_1, max_sectors_2); + sc->disableOnlineCtrlReset = + ci->properties.OnOffProperties.disableOnlineCtrlReset; out: if (ci) @@ -871,6 +988,7 @@ mfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state) struct mfi_command *cm = NULL; int error; + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO, (void **)log_state, sizeof(**log_state)); if (error) @@ -889,11 +1007,12 @@ mfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state) out: if (cm) mfi_release_command(cm); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); return (error); } -static int +int mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start) { struct mfi_evt_log_state *log_state = NULL; @@ -907,6 +1026,7 @@ mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start) if (seq_start == 0) { error = mfi_get_log_state(sc, &log_state); + sc->mfi_boot_seq_num = log_state->boot_seq_num; if (error) { if (log_state) kfree(log_state, M_MFIBUF); @@ -929,7 +1049,7 @@ mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start) return 0; } -static int +int mfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm) { @@ -978,8 +1098,7 @@ mfi_free(struct mfi_softc *sc) if (sc->mfi_irq != NULL) bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid, sc->mfi_irq); - if (sc->mfi_irq_type == PCI_INTR_TYPE_MSI) - pci_release_msi(sc->mfi_dev); + if (sc->mfi_sense_busaddr != 0) bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap); if (sc->mfi_sense != NULL) @@ -1004,6 +1123,64 @@ mfi_free(struct mfi_softc *sc) if (sc->mfi_comms_dmat != NULL) bus_dma_tag_destroy(sc->mfi_comms_dmat); + /* ThunderBolt contiguous memory free here */ + if (sc->mfi_flags & MFI_FLAGS_TBOLT) { + if (sc->mfi_tb_busaddr != 0) + bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap); + if (sc->request_message_pool != NULL) + bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool, + sc->mfi_tb_dmamap); + if (sc->mfi_tb_dmat != NULL) + bus_dma_tag_destroy(sc->mfi_tb_dmat); + + /* Version buffer memory free */ + /* Start LSIP200113393 */ + if (sc->verbuf_h_busaddr != 0) + bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap); + if (sc->verbuf != NULL) + bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf, + sc->verbuf_h_dmamap); + if (sc->verbuf_h_dmat != NULL) + bus_dma_tag_destroy(sc->verbuf_h_dmat); + + /* End LSIP200113393 */ + /* ThunderBolt INIT packet memory Free */ + if (sc->mfi_tb_init_busaddr != 0) + bus_dmamap_unload(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap); + if (sc->mfi_tb_init != NULL) + bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init, + sc->mfi_tb_init_dmamap); + if (sc->mfi_tb_init_dmat != NULL) + bus_dma_tag_destroy(sc->mfi_tb_init_dmat); + + /* ThunderBolt IOC Init Desc memory free here */ + if (sc->mfi_tb_ioc_init_busaddr != 0) + bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat, + sc->mfi_tb_ioc_init_dmamap); + if (sc->mfi_tb_ioc_init_desc != NULL) + bus_dmamem_free(sc->mfi_tb_ioc_init_dmat, + sc->mfi_tb_ioc_init_desc, + sc->mfi_tb_ioc_init_dmamap); + if (sc->mfi_tb_ioc_init_dmat != NULL) + bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat); + for (int i = 0; i < sc->mfi_max_fw_cmds; i++) { + if (sc->mfi_cmd_pool_tbolt != NULL) { + if (sc->mfi_cmd_pool_tbolt[i] != NULL) { + kfree(sc->mfi_cmd_pool_tbolt[i], + M_MFIBUF); + sc->mfi_cmd_pool_tbolt[i] = NULL; + } + } + } + if (sc->mfi_cmd_pool_tbolt != NULL) { + kfree(sc->mfi_cmd_pool_tbolt, M_MFIBUF); + sc->mfi_cmd_pool_tbolt = NULL; + } + if (sc->request_desc_pool != NULL) { + kfree(sc->request_desc_pool, M_MFIBUF); + sc->request_desc_pool = NULL; + } + } if (sc->mfi_buffer_dmat != NULL) bus_dma_tag_destroy(sc->mfi_buffer_dmat); if (sc->mfi_parent_dmat != NULL) @@ -1054,12 +1231,7 @@ mfi_intr(void *arg) if (sc->mfi_check_clear_intr(sc)) return; - /* - * Do a dummy read to flush the interrupt ACK that we just performed, - * ensuring that everything is really, truly consistent. - */ - (void)sc->mfi_read_fw_status(sc); - +restart: pi = sc->mfi_comms->hw_pi; ci = sc->mfi_comms->hw_ci; lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); @@ -1084,6 +1256,14 @@ mfi_intr(void *arg) mfi_startio(sc); lockmgr(&sc->mfi_io_lock, LK_RELEASE); + /* + * Dummy read to flush the bus; this ensures that the indexes are up + * to date. Restart processing if more commands have come it. + */ + (void)sc->mfi_read_fw_status(sc); + if (pi != sc->mfi_comms->hw_pi) + goto restart; + return; } @@ -1104,6 +1284,9 @@ mfi_shutdown(struct mfi_softc *sc) if (sc->mfi_aen_cm != NULL) mfi_abort(sc, sc->mfi_aen_cm); + if (sc->map_update_cmd != NULL) + mfi_abort(sc, sc->map_update_cmd); + dcmd = &cm->cm_frame->dcmd; dcmd->header.flags = MFI_FRAME_DIR_NONE; cm->cm_flags = MFI_CMD_POLLED; @@ -1117,14 +1300,15 @@ mfi_shutdown(struct mfi_softc *sc) lockmgr(&sc->mfi_io_lock, LK_RELEASE); return (error); } + static void mfi_syspdprobe(struct mfi_softc *sc) { struct mfi_frame_header *hdr; struct mfi_command *cm = NULL; struct mfi_pd_list *pdlist = NULL; - struct mfi_system_pd *syspd; - int error, i; + struct mfi_system_pd *syspd, *tmp; + int error, i, found; KKASSERT(lockstatus(&sc->mfi_config_lock, curthread) != 0); KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); @@ -1132,7 +1316,8 @@ mfi_syspdprobe(struct mfi_softc *sc) error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY, (void **)&pdlist, sizeof(*pdlist)); if (error) { - device_printf(sc->mfi_dev,"Error while forming syspd list\n"); + device_printf(sc->mfi_dev, + "Error while forming SYSTEM PD list\n"); goto out; } @@ -1140,7 +1325,8 @@ mfi_syspdprobe(struct mfi_softc *sc) cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST; cm->cm_frame->dcmd.mbox[1] = 0; if (mfi_mapcmd(sc, cm) != 0) { - device_printf(sc->mfi_dev, "Failed to get syspd device list\n"); + device_printf(sc->mfi_dev, + "Failed to get syspd device listing\n"); goto out; } bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap, @@ -1148,36 +1334,37 @@ mfi_syspdprobe(struct mfi_softc *sc) bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); hdr = &cm->cm_frame->header; if (hdr->cmd_status != MFI_STAT_OK) { - device_printf(sc->mfi_dev, "MFI_DCMD_PD_LIST_QUERY failed %x\n", - hdr->cmd_status); + device_printf(sc->mfi_dev, + "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status); goto out; } + /* Get each PD and add it to the system */ for (i = 0; i < pdlist->count; i++) { - if (pdlist->addr[i].device_id == pdlist->addr[i].encl_device_id) - goto skip_sys_pd_add; - /* Get each PD and add it to the system */ - if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) { - TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) { - if (syspd->pd_id == pdlist->addr[i].device_id) - goto skip_sys_pd_add; - } + if (pdlist->addr[i].device_id == + pdlist->addr[i].encl_device_id) + continue; + found = 0; + TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { + if (syspd->pd_id == pdlist->addr[i].device_id) + found = 1; } - mfi_add_sys_pd(sc,pdlist->addr[i].device_id); -skip_sys_pd_add: - ; + if (found == 0) + mfi_add_sys_pd(sc, pdlist->addr[i].device_id); } /* Delete SYSPD's whose state has been changed */ - if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) { - TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) { - for (i=0;icount;i++) { - if (syspd->pd_id == pdlist->addr[i].device_id) - goto skip_sys_pd_delete; - } + TAILQ_FOREACH_MUTABLE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) { + found = 0; + for (i = 0; i < pdlist->count; i++) { + if (syspd->pd_id == pdlist->addr[i].device_id) + found = 1; + } + if (found == 0) { + kprintf("DELETE\n"); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); get_mplock(); - device_delete_child(sc->mfi_dev,syspd->pd_dev); + device_delete_child(sc->mfi_dev, syspd->pd_dev); rel_mplock(); -skip_sys_pd_delete: - ; + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); } } out: @@ -1281,10 +1468,125 @@ format_class(int8_t class) static void mfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) { + struct mfi_system_pd *syspd = NULL; device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq, format_timestamp(detail->time), detail->evt_class.members.locale, - format_class(detail->evt_class.members.evt_class), detail->description); + format_class(detail->evt_class.members.evt_class), + detail->description); + + /* Don't act on old AEN's or while shutting down */ + if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching) + return; + + switch (detail->arg_type) { + case MR_EVT_ARGS_NONE: + if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) { + device_printf(sc->mfi_dev, "HostBus scan raised\n"); + if (mfi_detect_jbod_change) { + /* + * Probe for new SYSPD's and Delete + * invalid SYSPD's + */ + lockmgr(&sc->mfi_config_lock, LK_EXCLUSIVE); + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); + mfi_syspdprobe(sc); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + lockmgr(&sc->mfi_config_lock, LK_RELEASE); + } + } + break; + case MR_EVT_ARGS_LD_STATE: + /* + * During load time driver reads all the events starting + * from the one that has been logged after shutdown. Avoid + * these old events. + */ + if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) { + /* Remove the LD */ + struct mfi_disk *ld; + TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { + if (ld->ld_id == + detail->args.ld_state.ld.target_id) + break; + } + /* + Fix: for kernel panics when SSCD is removed + KASSERT(ld != NULL, ("volume dissappeared")); + */ + if (ld != NULL) { + get_mplock(); + device_delete_child(sc->mfi_dev, ld->ld_dev); + rel_mplock(); + } + } + break; + case MR_EVT_ARGS_PD: + if (detail->code == MR_EVT_PD_REMOVED) { + if (mfi_detect_jbod_change) { + /* + * If the removed device is a SYSPD then + * delete it + */ + TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, + pd_link) { + if (syspd->pd_id == + detail->args.pd.device_id) { + get_mplock(); + device_delete_child( + sc->mfi_dev, + syspd->pd_dev); + rel_mplock(); + break; + } + } + } + } + if (detail->code == MR_EVT_PD_INSERTED) { + if (mfi_detect_jbod_change) { + /* Probe for new SYSPD's */ + lockmgr(&sc->mfi_config_lock, LK_EXCLUSIVE); + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); + mfi_syspdprobe(sc); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + lockmgr(&sc->mfi_config_lock, LK_RELEASE); + } + } + break; + } +} + +static void +mfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) +{ + struct mfi_evt_queue_elm *elm; + + KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); + elm = kmalloc(sizeof(*elm), M_MFIBUF, M_NOWAIT | M_ZERO); + if (elm == NULL) + return; + memcpy(&elm->detail, detail, sizeof(*detail)); + TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link); + taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task); +} + +static void +mfi_handle_evt(void *context, int pending) +{ + TAILQ_HEAD(,mfi_evt_queue_elm) queue; + struct mfi_softc *sc; + struct mfi_evt_queue_elm *elm; + + sc = context; + TAILQ_INIT(&queue); + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); + TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + while ((elm = TAILQ_FIRST(&queue)) != NULL) { + TAILQ_REMOVE(&queue, elm, link); + mfi_decode_evt(sc, &elm->detail); + kfree(elm, M_MFIBUF); + } } static int @@ -1310,12 +1612,16 @@ mfi_aen_register(struct mfi_softc *sc, int seq, int locale) < current_aen.members.evt_class) current_aen.members.evt_class = prior_aen.members.evt_class; + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); mfi_abort(sc, sc->mfi_aen_cm); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); } } + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT, (void **)&ed, sizeof(*ed)); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); if (error) { goto out; } @@ -1326,10 +1632,13 @@ mfi_aen_register(struct mfi_softc *sc, int seq, int locale) cm->cm_flags = MFI_CMD_DATAIN; cm->cm_complete = mfi_aen_complete; + sc->last_seq_num = seq; sc->mfi_aen_cm = cm; + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); mfi_enqueue_ready(cm); mfi_startio(sc); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); out: return (error); @@ -1345,6 +1654,8 @@ mfi_aen_complete(struct mfi_command *cm) int seq = 0, aborted = 0; sc = cm->cm_sc; + KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); + hdr = &cm->cm_frame->header; if (sc->mfi_aen_cm == NULL) @@ -1361,13 +1672,10 @@ mfi_aen_complete(struct mfi_command *cm) KNOTE(&sc->mfi_kq.ki_note, 0); } detail = cm->cm_data; - /* - * XXX If this function is too expensive or is recursive, then - * events should be put onto a queue and processed later. - */ - mfi_decode_evt(sc, detail); + mfi_queue_evt(sc, detail); seq = detail->seq + 1; - TAILQ_FOREACH_MUTABLE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) { + TAILQ_FOREACH_MUTABLE(mfi_aen_entry, &sc->mfi_aen_pids, + aen_link, tmp) { TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, aen_link); lwkt_gettoken(&proc_token); @@ -1384,7 +1692,9 @@ mfi_aen_complete(struct mfi_command *cm) /* set it up again so the driver can catch more events */ if (!aborted) { + lockmgr(&sc->mfi_io_lock, LK_RELEASE); mfi_aen_setup(sc, seq); + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); } } @@ -1398,7 +1708,6 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) struct mfi_evt_list *el; union mfi_evt class_locale; int error, i, seq, size; - uint32_t context = 0; class_locale.members.reserved = 0; class_locale.members.locale = mfi_event_locale; @@ -1411,22 +1720,20 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) return (ENOMEM); for (seq = start_seq;;) { + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); if ((cm = mfi_dequeue_free(sc)) == NULL) { kfree(el, M_MFIBUF); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); return (EBUSY); } - /* Zero out the MFI frame */ - context = cm->cm_frame->header.context; - bzero(cm->cm_frame, sizeof(union mfi_frame)); - cm->cm_frame->header.context = context; + lockmgr(&sc->mfi_io_lock, LK_RELEASE); dcmd = &cm->cm_frame->dcmd; bzero(dcmd->mbox, MFI_MBOX_SIZE); dcmd->header.cmd = MFI_CMD_DCMD; dcmd->header.timeout = 0; dcmd->header.data_len = size; - dcmd->header.scsi_status = 0; dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET; ((uint32_t *)&dcmd->mbox)[0] = seq; ((uint32_t *)&dcmd->mbox)[1] = class_locale.word; @@ -1436,29 +1743,38 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) cm->cm_data = el; cm->cm_len = size; + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); if ((error = mfi_mapcmd(sc, cm)) != 0) { device_printf(sc->mfi_dev, "Failed to get controller entries\n"); mfi_release_command(cm); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); break; } + lockmgr(&sc->mfi_io_lock, LK_RELEASE); bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) { + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); mfi_release_command(cm); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); break; } if (dcmd->header.cmd_status != MFI_STAT_OK) { device_printf(sc->mfi_dev, "Error %d fetching controller entries\n", dcmd->header.cmd_status); + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); mfi_release_command(cm); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); break; } + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); mfi_release_command(cm); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); for (i = 0; i < el->count; i++) { /* @@ -1474,7 +1790,9 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) else if (el->event[i].seq < start_seq) break; } - mfi_decode_evt(sc, &el->event[i]); + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); + mfi_queue_evt(sc, &el->event[i]); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); } seq = el->event[el->count - 1].seq + 1; } @@ -1515,7 +1833,7 @@ mfi_add_ld(struct mfi_softc *sc, int id) mfi_add_ld_complete(cm); } else { mfi_release_command(cm); - if(ld_info) /* SSCD drives ld_info free here */ + if (ld_info) /* SSCD drives ld_info free here */ kfree(ld_info, M_MFIBUF); } return (0); @@ -1558,7 +1876,7 @@ mfi_add_ld_complete(struct mfi_command *cm) } static int -mfi_add_sys_pd(struct mfi_softc *sc,int id) +mfi_add_sys_pd(struct mfi_softc *sc, int id) { struct mfi_command *cm; struct mfi_dcmd_frame *dcmd = NULL; @@ -1567,13 +1885,14 @@ mfi_add_sys_pd(struct mfi_softc *sc,int id) KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); - error = mfi_dcmd_command(sc,&cm,MFI_DCMD_PD_GET_INFO, + error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO, (void **)&pd_info, sizeof(*pd_info)); if (error) { device_printf(sc->mfi_dev, - "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n", error); + "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n", + error); if (pd_info) - kfree(pd_info,M_MFIBUF); + kfree(pd_info, M_MFIBUF); return (error); } cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; @@ -1584,12 +1903,12 @@ mfi_add_sys_pd(struct mfi_softc *sc,int id) if (mfi_mapcmd(sc, cm) != 0) { device_printf(sc->mfi_dev, "Failed to get physical drive info %d\n", id); - kfree(pd_info,M_MFIBUF); + kfree(pd_info, M_MFIBUF); return (0); } bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(sc->mfi_buffer_dmat,cm->cm_dmamap); + bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); mfi_add_sys_pd_complete(cm); return (0); } @@ -1612,7 +1931,7 @@ mfi_add_sys_pd_complete(struct mfi_command *cm) return; } if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) { - device_printf(sc->mfi_dev,"PD=%x is not SYSTEM PD\n", + device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n", pd_info->ref.v.device_id); kfree(pd_info, M_MFIBUF); mfi_release_command(cm); @@ -1655,7 +1974,7 @@ mfi_bio_command(struct mfi_softc *sc) else cm = mfi_build_ldio(sc, bio); if (!cm) - mfi_enqueue_bio(sc,bio); + mfi_enqueue_bio(sc, bio); return cm; } @@ -1666,7 +1985,7 @@ mfi_build_syspdio(struct mfi_softc *sc, struct bio *bio) struct buf *bp; struct mfi_system_pd *disk; struct mfi_pass_frame *pass; - int flags = 0,blkcount = 0; + int flags = 0, blkcount = 0; uint32_t context = 0; if ((cm = mfi_dequeue_free(sc)) == NULL) @@ -1710,13 +2029,8 @@ mfi_build_syspdio(struct mfi_softc *sc, struct bio *bio) pass->header.sense_len = MFI_SENSE_LEN; pass->header.data_len = bp->b_bcount; pass->header.cdb_len = 10; -#if defined(__x86_64__) - pass->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF); - pass->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000) >> 32; -#else - pass->sense_addr_lo = cm->cm_sense_busaddr; - pass->sense_addr_hi = 0; -#endif + pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; + pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); cm->cm_complete = mfi_bio_complete; cm->cm_private = bio; cm->cm_data = bp->b_data; @@ -1728,7 +2042,7 @@ mfi_build_syspdio(struct mfi_softc *sc, struct bio *bio) } static struct mfi_command * -mfi_build_ldio(struct mfi_softc *sc,struct bio *bio) +mfi_build_ldio(struct mfi_softc *sc, struct bio *bio) { struct mfi_io_frame *io; struct buf *bp; @@ -1742,7 +2056,7 @@ mfi_build_ldio(struct mfi_softc *sc,struct bio *bio) /* Zero out the MFI frame */ context = cm->cm_frame->header.context; - bzero(cm->cm_frame,sizeof(union mfi_frame)); + bzero(cm->cm_frame, sizeof(union mfi_frame)); cm->cm_frame->header.context = context; bp = bio->bio_buf; io = &cm->cm_frame->io; @@ -1768,13 +2082,8 @@ mfi_build_ldio(struct mfi_softc *sc,struct bio *bio) io->header.scsi_status = 0; io->header.sense_len = MFI_SENSE_LEN; io->header.data_len = blkcount; -#if defined(__x86_64__) - io->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF); - io->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000) >> 32; -#else - io->sense_addr_lo = cm->cm_sense_busaddr; - io->sense_addr_hi = 0; -#endif + io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; + io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); io->lba_hi = ((bio->bio_offset / MFI_SECTOR_LEN) & 0xffffffff00000000) >> 32; io->lba_lo = (bio->bio_offset / MFI_SECTOR_LEN) & 0xffffffff; cm->cm_complete = mfi_bio_complete; @@ -1849,14 +2158,14 @@ mfi_startio(struct mfi_softc *sc) } } -static int +int mfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm) { int error, polled; KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); - if (cm->cm_data != NULL) { + if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP)) { polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0; error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap, cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled); @@ -1865,7 +2174,10 @@ mfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm) return (0); } } else { - error = mfi_send_frame(sc, cm); + if (sc->MFA_enabled) + error = mfi_tbolt_send_frame(sc, cm); + else + error = mfi_send_frame(sc, cm); } return (error); @@ -1879,8 +2191,7 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) union mfi_sgl *sgl; struct mfi_softc *sc; int i, j, first, dir; - int sgl_mapped = 0; - int sge_size = 0; + int sge_size; cm = (struct mfi_command *)arg; sc = cm->cm_sc; @@ -1910,10 +2221,9 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) sgl->sg_skinny[i].flag = 0; } hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64; - sgl_mapped = 1; sge_size = sizeof(struct mfi_sg_skinny); - } - if (!sgl_mapped) { + hdr->sg_count = nsegs; + } else { j = 0; if (cm->cm_frame->header.cmd == MFI_CMD_STP) { first = cm->cm_stp_len; @@ -1932,7 +2242,6 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) sgl->sg32[j++].len = segs[i].ds_len - first; first = 0; } - sge_size = sizeof(struct mfi_sg32); } else { for (i = 0; i < nsegs; i++) { sgl->sg64[j].addr = segs[i].ds_addr + first; @@ -1940,11 +2249,10 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) first = 0; } hdr->flags |= MFI_FRAME_SGL64; - sge_size = sizeof(struct mfi_sg64); } hdr->sg_count = j; - } else - hdr->sg_count = nsegs; + sge_size = sc->mfi_sge_size; + } dir = 0; if (cm->cm_flags & MFI_CMD_DATAIN) { @@ -1955,8 +2263,6 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) dir |= BUS_DMASYNC_PREWRITE; hdr->flags |= MFI_FRAME_DIR_WRITE; } - if (cm->cm_frame->header.cmd == MFI_CMD_STP) - dir |= BUS_DMASYNC_PREWRITE; bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir); cm->cm_flags |= MFI_CMD_MAPPED; @@ -1966,10 +2272,13 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) * least 1 frame, so don't compensate for the modulo of the * following division. */ - cm->cm_total_frame_size += (sge_size * nsegs); + cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs); cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; - mfi_send_frame(sc, cm); + if (sc->MFA_enabled) + mfi_tbolt_send_frame(sc, cm); + else + mfi_send_frame(sc, cm); } static int @@ -2003,7 +2312,7 @@ mfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm) if (cm->cm_extra_frames > 7) cm->cm_extra_frames = 7; - sc->mfi_issue_cmd(sc,cm->cm_frame_busaddr,cm->cm_extra_frames); + sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames); if ((cm->cm_flags & MFI_CMD_POLLED) == 0) return (0); @@ -2018,14 +2327,14 @@ mfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm) if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { device_printf(sc->mfi_dev, "Frame %p timed out " - "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode); + "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode); return (ETIMEDOUT); } return (0); } -static void +void mfi_complete(struct mfi_softc *sc, struct mfi_command *cm) { int dir; @@ -2075,22 +2384,20 @@ mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort) abort->header.flags = 0; abort->header.scsi_status = 0; abort->abort_context = cm_abort->cm_frame->header.context; -#if defined(__x86_64__) - abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr & 0xFFFFFFFF; - abort->abort_mfi_addr_hi = (cm_abort->cm_frame_busaddr & 0xFFFFFFFF00000000 ) >> 32 ; -#else - abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr; - abort->abort_mfi_addr_hi = 0; -#endif + abort->abort_mfi_addr_lo = (uint32_t)cm_abort->cm_frame_busaddr; + abort->abort_mfi_addr_hi = + (uint32_t)((uint64_t)cm_abort->cm_frame_busaddr >> 32); cm->cm_data = NULL; cm->cm_flags = MFI_CMD_POLLED; - sc->mfi_aen_cm->cm_aen_abort = 1; + if (sc->mfi_aen_cm) + sc->mfi_aen_cm->cm_aen_abort = 1; mfi_mapcmd(sc, cm); mfi_release_command(cm); while (i < 5 && sc->mfi_aen_cm != NULL) { - lksleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", 5 * hz); + lksleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", + 5 * hz); i++; } @@ -2098,7 +2405,8 @@ mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort) } int -mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len) +mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, + int len) { struct mfi_command *cm; struct mfi_io_frame *io; @@ -2121,13 +2429,8 @@ mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len) io->header.scsi_status = 0; io->header.sense_len = MFI_SENSE_LEN; io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; -#if defined(__x86_64__) - io->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF); - io->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000 ) >> 32; -#else - io->sense_addr_lo = cm->cm_sense_busaddr; - io->sense_addr_hi = 0; -#endif + io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; + io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); io->lba_hi = (lba & 0xffffffff00000000) >> 32; io->lba_lo = lba & 0xffffffff; cm->cm_data = virt; @@ -2175,13 +2478,8 @@ mfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, pass->header.sense_len = MFI_SENSE_LEN; pass->header.data_len = len; pass->header.cdb_len = 10; -#if defined(__x86_64__) - pass->sense_addr_lo = (cm->cm_sense_busaddr & 0xFFFFFFFF); - pass->sense_addr_hi = (cm->cm_sense_busaddr & 0xFFFFFFFF00000000 ) >> 32; -#else - pass->sense_addr_lo = cm->cm_sense_busaddr; - pass->sense_addr_hi = 0; -#endif + pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; + pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); cm->cm_data = virt; cm->cm_len = len; cm->cm_sg = &pass->sgl; @@ -2264,7 +2562,10 @@ mfi_config_unlock(struct mfi_softc *sc, int locked) lockmgr(&sc->mfi_config_lock, LK_RELEASE); } -/* Perform pre-issue checks on commands from userland and possibly veto them. */ +/* + * Perform pre-issue checks on commands from userland and possibly veto + * them. + */ static int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm) { @@ -2305,16 +2606,14 @@ mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm) mbox = (uint16_t *)cm->cm_frame->dcmd.mbox; syspd_id = mbox[0]; if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { - if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) { - TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { - if (syspd->pd_id == syspd_id) - break; - } + TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { + if (syspd->pd_id == syspd_id) + break; } } else { break; } - if(syspd) + if (syspd) error = mfi_syspd_disable(syspd); break; default: @@ -2372,22 +2671,153 @@ mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm) mbox = (uint16_t *)cm->cm_frame->dcmd.mbox; syspd_id = mbox[0]; if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { - if (!TAILQ_EMPTY(&sc->mfi_syspd_tqh)) { - TAILQ_FOREACH(syspd,&sc->mfi_syspd_tqh,pd_link) { - if (syspd->pd_id == syspd_id) - break; - } + TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { + if (syspd->pd_id == syspd_id) + break; } } else { break; } /* If the transition fails then enable the syspd again */ - if(syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK) + if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK) mfi_syspd_enable(syspd); break; } } +static int +mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm) +{ + struct mfi_config_data *conf_data = cm->cm_data; + struct mfi_command *ld_cm = NULL; + struct mfi_ld_info *ld_info = NULL; + int error = 0; + + if ((cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) && + (conf_data->ld[0].params.isSSCD == 1)) { + error = 1; + } else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) { + error = mfi_dcmd_command(sc, &ld_cm, MFI_DCMD_LD_GET_INFO, + (void **)&ld_info, sizeof(*ld_info)); + if (error) { + device_printf(sc->mfi_dev, "Failed to allocate" + "MFI_DCMD_LD_GET_INFO %d", error); + if (ld_info) + kfree(ld_info, M_MFIBUF); + return 0; + } + ld_cm->cm_flags = MFI_CMD_DATAIN; + ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0]; + ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0]; + if (mfi_wait_command(sc, ld_cm) != 0) { + device_printf(sc->mfi_dev, "failed to get log drv\n"); + mfi_release_command(ld_cm); + kfree(ld_info, M_MFIBUF); + return 0; + } + + if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) { + kfree(ld_info, M_MFIBUF); + mfi_release_command(ld_cm); + return 0; + } else { + ld_info = (struct mfi_ld_info *)ld_cm->cm_private; + } + + if (ld_info->ld_config.params.isSSCD == 1) + error = 1; + + mfi_release_command(ld_cm); + kfree(ld_info, M_MFIBUF); + } + return error; +} + +static int +mfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg) +{ + uint8_t i; + struct mfi_ioc_packet *ioc; + ioc = (struct mfi_ioc_packet *)arg; + int sge_size, error; + struct megasas_sge *kern_sge; + + memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr)); + kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off); + cm->cm_frame->header.sg_count = ioc->mfi_sge_count; + + if (sizeof(bus_addr_t) == 8) { + cm->cm_frame->header.flags |= MFI_FRAME_SGL64; + cm->cm_extra_frames = 2; + sge_size = sizeof(struct mfi_sg64); + } else { + cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; + sge_size = sizeof(struct mfi_sg32); + } + + cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count); + for (i = 0; i < ioc->mfi_sge_count; i++) { + if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + ioc->mfi_sgl[i].iov_len,/* maxsize */ + 2, /* nsegments */ + ioc->mfi_sgl[i].iov_len,/* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + &sc->mfi_kbuff_arr_dmat[i])) { + device_printf(sc->mfi_dev, + "Cannot allocate mfi_kbuff_arr_dmat tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i], + (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT, + &sc->mfi_kbuff_arr_dmamap[i])) { + device_printf(sc->mfi_dev, + "Cannot allocate mfi_kbuff_arr_dmamap memory\n"); + return (ENOMEM); + } + + bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i], + sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i], + ioc->mfi_sgl[i].iov_len, mfi_addr_cb, + &sc->mfi_kbuff_arr_busaddr[i], 0); + + if (!sc->kbuff_arr[i]) { + device_printf(sc->mfi_dev, + "Could not allocate memory for kbuff_arr info\n"); + return -1; + } + kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i]; + kern_sge[i].length = ioc->mfi_sgl[i].iov_len; + + if (sizeof(bus_addr_t) == 8) { + cm->cm_frame->stp.sgl.sg64[i].addr = + kern_sge[i].phys_addr; + cm->cm_frame->stp.sgl.sg64[i].len = + ioc->mfi_sgl[i].iov_len; + } else { + cm->cm_frame->stp.sgl.sg32[i].len = + kern_sge[i].phys_addr; + cm->cm_frame->stp.sgl.sg32[i].len = + ioc->mfi_sgl[i].iov_len; + } + + error = copyin(ioc->mfi_sgl[i].iov_base, + sc->kbuff_arr[i], + ioc->mfi_sgl[i].iov_len); + if (error != 0) { + device_printf(sc->mfi_dev, "Copy in failed\n"); + return error; + } + } + + cm->cm_flags |=MFI_CMD_MAPPED; + return 0; +} + static int mfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc) { @@ -2453,59 +2883,7 @@ out: return (error); } -#ifdef __x86_64__ #define PTRIN(p) ((void *)(uintptr_t)(p)) -#else -#define PTRIN(p) (p) -#endif - -static int -mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm) -{ - struct mfi_config_data *conf_data = cm->cm_data; - struct mfi_command *ld_cm = NULL; - struct mfi_ld_info *ld_info = NULL; - int error = 0; - - if ((cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) && - (conf_data->ld[0].params.isSSCD == 1)) { - error = 1; - } else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) { - error = mfi_dcmd_command(sc, &ld_cm, MFI_DCMD_LD_GET_INFO, - (void **)&ld_info, sizeof(*ld_info)); - if (error) { - device_printf(sc->mfi_dev,"Failed to allocate " - "MFI_DCMD_LD_GET_INFO %d", error); - if (ld_info) - kfree(ld_info, M_MFIBUF); - return 0; - } - ld_cm->cm_flags = MFI_CMD_DATAIN; - ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0]; - ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0]; - if (mfi_wait_command(sc, ld_cm) != 0) { - device_printf(sc->mfi_dev, "failed to get log drv\n"); - mfi_release_command(ld_cm); - kfree(ld_info, M_MFIBUF); - return 0; - } - - if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) { - kfree(ld_info, M_MFIBUF); - mfi_release_command(ld_cm); - return 0; - } else { - ld_info = (struct mfi_ld_info *)ld_cm->cm_private; - } - - if (ld_info->ld_config.params.isSSCD == 1) - error = 1; - - mfi_release_command(ld_cm); - kfree(ld_info, M_MFIBUF); - } - return error; -} static int mfi_ioctl(struct dev_ioctl_args *ap) @@ -2517,26 +2895,29 @@ mfi_ioctl(struct dev_ioctl_args *ap) struct mfi_softc *sc; union mfi_statrequest *ms; struct mfi_ioc_packet *ioc; -#ifdef __x86_64__ - struct mfi_ioc_packet32 *ioc32; -#endif struct mfi_ioc_aen *aen; struct mfi_command *cm = NULL; uint32_t context; union mfi_sense_ptr sense_ptr; uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0; size_t len; - int i; + int i, res; struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg; -#ifdef __x86_64__ - struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg; - struct mfi_ioc_passthru iop_swab; -#endif int error, locked; + union mfi_sgl *sgl; sc = dev->si_drv1; error = 0; + if (sc->adpreset) + return EBUSY; + + if (sc->hw_crit_error) + return EBUSY; + + if (sc->issuepend_done == 0) + return EBUSY; + switch (cmd) { case MFIIO_STATS: ms = (union mfi_statrequest *)arg; @@ -2578,9 +2959,6 @@ mfi_ioctl(struct dev_ioctl_args *ap) break; } case MFI_CMD: -#ifdef __x86_64__ - case MFI_CMD32: -#endif { devclass_t devclass; ioc = (struct mfi_ioc_packet *)arg; @@ -2604,9 +2982,10 @@ mfi_ioctl(struct dev_ioctl_args *ap) * will clobber some data */ context = cm->cm_frame->header.context; + cm->cm_frame->header.context = cm->cm_index; bcopy(ioc->mfi_frame.raw, cm->cm_frame, - 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */ + 2 * MEGAMFI_FRAME_SIZE); cm->cm_total_frame_size = (sizeof(union mfi_sgl) * ioc->mfi_sge_count) + ioc->mfi_sgl_off; cm->cm_frame->header.scsi_status = 0; @@ -2615,6 +2994,7 @@ mfi_ioctl(struct dev_ioctl_args *ap) cm->cm_sg = (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off]; } + sgl = cm->cm_sg; cm->cm_flags = 0; if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN) cm->cm_flags |= MFI_CMD_DATAIN; @@ -2625,18 +3005,7 @@ mfi_ioctl(struct dev_ioctl_args *ap) cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT; cm->cm_len = cm->cm_frame->header.data_len; if (cm->cm_frame->header.cmd == MFI_CMD_STP) { -#ifdef __x86_64__ - if (cmd == MFI_CMD) { -#endif - /* Native */ - cm->cm_stp_len = ioc->mfi_sgl[0].iov_len; -#ifdef __x86_64__ - } else { - /* 32bit on 64bit */ - ioc32 = (struct mfi_ioc_packet32 *)ioc; - cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len; - } -#endif + cm->cm_stp_len = ioc->mfi_sgl[0].iov_len; cm->cm_len += cm->cm_stp_len; } if (cm->cm_len && @@ -2650,49 +3019,38 @@ mfi_ioctl(struct dev_ioctl_args *ap) /* restore header context */ cm->cm_frame->header.context = context; - temp = data; - if ((cm->cm_flags & MFI_CMD_DATAOUT) || - (cm->cm_frame->header.cmd == MFI_CMD_STP)) { - for (i = 0; i < ioc->mfi_sge_count; i++) { -#ifdef __x86_64__ - if (cmd == MFI_CMD) { -#endif - /* Native */ + if (cm->cm_frame->header.cmd == MFI_CMD_STP) { + res = mfi_stp_cmd(sc, cm, arg); + if (res != 0) + goto out; + } else { + temp = data; + if ((cm->cm_flags & MFI_CMD_DATAOUT) || + (cm->cm_frame->header.cmd == MFI_CMD_STP)) { + for (i = 0; i < ioc->mfi_sge_count; i++) { addr = ioc->mfi_sgl[i].iov_base; len = ioc->mfi_sgl[i].iov_len; -#ifdef __x86_64__ - } else { - /* 32bit on 64bit */ - ioc32 = (struct mfi_ioc_packet32 *)ioc; - addr = PTRIN(ioc32->mfi_sgl[i].iov_base); - len = ioc32->mfi_sgl[i].iov_len; + error = copyin(addr, temp, len); + if (error != 0) { + device_printf(sc->mfi_dev, + "Copy in failed\n"); + goto out; + } + temp = &temp[len]; } -#endif - error = copyin(addr, temp, len); - if (error != 0) { - device_printf(sc->mfi_dev, - "Copy in failed\n"); - goto out; - } - temp = &temp[len]; } } if (cm->cm_frame->header.cmd == MFI_CMD_DCMD) - locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode); + locked = mfi_config_lock(sc, + cm->cm_frame->dcmd.opcode); if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { -#if defined(__x86_64__) cm->cm_frame->pass.sense_addr_lo = - (cm->cm_sense_busaddr & 0xFFFFFFFF); + (uint32_t)cm->cm_sense_busaddr; cm->cm_frame->pass.sense_addr_hi = - (cm->cm_sense_busaddr& 0xFFFFFFFF00000000) >> 32; -#else - cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr; - cm->cm_frame->pass.sense_addr_hi = 0; -#endif + (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); } - lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); skip_pre_post = mfi_check_for_sscd(sc, cm); if (!skip_pre_post) { @@ -2714,31 +3072,21 @@ mfi_ioctl(struct dev_ioctl_args *ap) mfi_check_command_post(sc, cm); lockmgr(&sc->mfi_io_lock, LK_RELEASE); - temp = data; - if ((cm->cm_flags & MFI_CMD_DATAIN) || - (cm->cm_frame->header.cmd == MFI_CMD_STP)) { - for (i = 0; i < ioc->mfi_sge_count; i++) { -#ifdef __x86_64__ - if (cmd == MFI_CMD) { -#endif - /* Native */ + if (cm->cm_frame->header.cmd != MFI_CMD_STP) { + temp = data; + if ((cm->cm_flags & MFI_CMD_DATAIN) || + (cm->cm_frame->header.cmd == MFI_CMD_STP)) { + for (i = 0; i < ioc->mfi_sge_count; i++) { addr = ioc->mfi_sgl[i].iov_base; len = ioc->mfi_sgl[i].iov_len; -#ifdef __x86_64__ - } else { - /* 32bit on 64bit */ - ioc32 = (struct mfi_ioc_packet32 *)ioc; - addr = PTRIN(ioc32->mfi_sgl[i].iov_base); - len = ioc32->mfi_sgl[i].iov_len; + error = copyout(temp, addr, len); + if (error != 0) { + device_printf(sc->mfi_dev, + "Copy out failed\n"); + goto out; + } + temp = &temp[len]; } -#endif - error = copyout(temp, addr, len); - if (error != 0) { - device_printf(sc->mfi_dev, - "Copy out failed\n"); - goto out; - } - temp = &temp[len]; } } @@ -2747,14 +3095,6 @@ mfi_ioctl(struct dev_ioctl_args *ap) bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off], &sense_ptr.sense_ptr_data[0], sizeof(sense_ptr.sense_ptr_data)); -#ifdef __x86_64__ - if (cmd != MFI_CMD) { - /* - * not 64bit native so zero out any address - * over 32bit */ - sense_ptr.addr.high = 0; - } -#endif error = copyout(cm->cm_sense, sense_ptr.user_space, ioc->mfi_sense_len); if (error != 0) { @@ -2769,6 +3109,26 @@ out: mfi_config_unlock(sc, locked); if (data) kfree(data, M_MFIBUF); + if (cm->cm_frame->header.cmd == MFI_CMD_STP) { + for (i = 0; i < 2; i++) { + if (sc->kbuff_arr[i]) { + if (sc->mfi_kbuff_arr_busaddr != 0) + bus_dmamap_unload( + sc->mfi_kbuff_arr_dmat[i], + sc->mfi_kbuff_arr_dmamap[i] + ); + if (sc->kbuff_arr[i] != NULL) + bus_dmamem_free( + sc->mfi_kbuff_arr_dmat[i], + sc->kbuff_arr[i], + sc->mfi_kbuff_arr_dmamap[i] + ); + if (sc->mfi_kbuff_arr_dmat[i] != NULL) + bus_dma_tag_destroy( + sc->mfi_kbuff_arr_dmat[i]); + } + } + } if (cm) { lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); mfi_release_command(cm); @@ -2825,20 +3185,8 @@ out: cmd, arg, flag)); break; } -#ifdef __x86_64__ - case MFIIO_PASSTHRU32: - iop_swab.ioc_frame = iop32->ioc_frame; - iop_swab.buf_size = iop32->buf_size; - iop_swab.buf = PTRIN(iop32->buf); - iop = &iop_swab; - /* FALLTHROUGH */ -#endif case MFIIO_PASSTHRU: error = mfi_user_command(sc, iop); -#ifdef __x86_64__ - if (cmd == MFIIO_PASSTHRU32) - iop32->ioc_frame = iop_swab.ioc_frame; -#endif break; default: device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); @@ -2934,15 +3282,10 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag) locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode); if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { -#if defined(__x86_64__) cm->cm_frame->pass.sense_addr_lo = - (cm->cm_sense_busaddr & 0xFFFFFFFF); + (uint32_t)cm->cm_sense_busaddr; cm->cm_frame->pass.sense_addr_hi = - (cm->cm_sense_busaddr & 0xFFFFFFFF00000000) >> 32; -#else - cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr; - cm->cm_frame->pass.sense_addr_hi = 0; -#endif + (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); } lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); @@ -3145,8 +3488,8 @@ mfi_dump_all(void) TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) { if (cm->cm_timestamp < deadline) { device_printf(sc->mfi_dev, - "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm, - (int)(time_second - cm->cm_timestamp)); + "COMMAND %p TIMEOUT AFTER %d SECONDS\n", + cm, (int)(time_second - cm->cm_timestamp)); MFI_PRINT_CMD(cm); timedout++; } @@ -3172,17 +3515,28 @@ mfi_timeout(void *data) int timedout = 0; deadline = time_second - MFI_CMD_TIMEOUT; + if (sc->adpreset == 0) { + if (!mfi_tbolt_reset(sc)) { + callout_reset(&sc->mfi_watchdog_callout, + MFI_CMD_TIMEOUT * hz, mfi_timeout, sc); + return; + } + } lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) { if (sc->mfi_aen_cm == cm) continue; if ((sc->mfi_aen_cm != cm) && (cm->cm_timestamp < deadline)) { - device_printf(sc->mfi_dev, - "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm, - (int)(time_second - cm->cm_timestamp)); - MFI_PRINT_CMD(cm); - MFI_VALIDATE_CMD(sc, cm); - timedout++; + if (sc->adpreset != 0 && sc->issuepend_done == 0) { + cm->cm_timestamp = time_second; + } else { + device_printf(sc->mfi_dev, + "COMMAND %p TIMEOUT AFTER %d SECONDS\n", + cm, (int)(time_second - cm->cm_timestamp)); + MFI_PRINT_CMD(cm); + MFI_VALIDATE_CMD(sc, cm); + timedout++; + } } } diff --git a/sys/dev/raid/mfi/mfi_cam.c b/sys/dev/raid/mfi/mfi_cam.c index d4fc2c08f0..b7a8ca259d 100644 --- a/sys/dev/raid/mfi/mfi_cam.c +++ b/sys/dev/raid/mfi/mfi_cam.c @@ -22,38 +22,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - */ -/*- - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Copyright 1994-2009 The FreeBSD Project. - * All rights reserved. - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfi_cam.c,v 1.7 2011/10/13 20:06:19 marius Exp $ + * FreeBSD projects/head_mfi/ r232949 */ #include "opt_mfi.h" @@ -151,6 +122,7 @@ mfip_attach(device_t dev) device_get_unit(dev), &mfisc->mfi_io_lock, 1, MFI_SCSI_MAX_CMDS, sc->devq); if (sc->sim == NULL) { + cam_simq_release(sc->devq); device_printf(dev, "CAM SIM attach failed\n"); return (EINVAL); } @@ -159,6 +131,7 @@ mfip_attach(device_t dev) if (xpt_bus_register(sc->sim, 0) != 0) { device_printf(dev, "XPT bus registration failed\n"); cam_sim_free(sc->sim); + cam_simq_release(sc->devq); lockmgr(&mfisc->mfi_io_lock, LK_RELEASE); return (EINVAL); } @@ -183,6 +156,9 @@ mfip_detach(device_t dev) lockmgr(&sc->mfi_sc->mfi_io_lock, LK_RELEASE); } + if (sc->devq != NULL) + cam_simq_release(sc->devq); + return (0); } diff --git a/sys/dev/raid/mfi/mfi_debug.c b/sys/dev/raid/mfi/mfi_debug.c index e3b5e741a6..648f855a48 100644 --- a/sys/dev/raid/mfi/mfi_debug.c +++ b/sys/dev/raid/mfi/mfi_debug.c @@ -24,6 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/dev/mfi/mfi_debug.c,v 1.3 2006/10/16 04:18:38 scottl Exp $ + * FreeBSD projects/head_mfi/ r228320 */ #include "opt_mfi.h" @@ -58,7 +59,8 @@ mfi_print_frame_flags(device_t dev, uint32_t flags) "\2SGL64" "\3SENSE64" "\4WRITE" - "\5READ"); + "\5READ" + "\6IEEESGL"); } static void @@ -68,7 +70,15 @@ mfi_print_sgl(struct mfi_frame_header *hdr, union mfi_sgl *sgl, int count) kprintf("SG List:\n"); for (i = 0; i < count; i++) { - if (hdr->flags & MFI_FRAME_SGL64) { + if (hdr->flags & MFI_FRAME_IEEE_SGL) { + kprintf("0x%lx:%06d ", (u_long)sgl->sg_skinny[i].addr, + sgl->sg_skinny[i].len); + columns += 26; + if (columns > 77) { + kprintf("\n"); + columns = 0; + } + } else if (hdr->flags & MFI_FRAME_SGL64) { kprintf("0x%lx:%06d ", (u_long)sgl->sg64[i].addr, sgl->sg64[i].len); columns += 26; @@ -235,7 +245,12 @@ mfi_validate_sg(struct mfi_softc *sc, struct mfi_command *cm, hdr = &cm->cm_frame->header; count = 0; for (i = 0; i < hdr->sg_count; i++) { - count += cm->cm_sg->sg32[i].len; + if (hdr->flags & MFI_FRAME_IEEE_SGL) + count += cm->cm_sg->sg_skinny[i].len; + else if (hdr->flags & MFI_FRAME_SGL64) + count += cm->cm_sg->sg64[i].len; + else + count += cm->cm_sg->sg32[i].len; } /* count++; diff --git a/sys/dev/raid/mfi/mfi_disk.c b/sys/dev/raid/mfi/mfi_disk.c index 53534b16c7..eeef124bf3 100644 --- a/sys/dev/raid/mfi/mfi_disk.c +++ b/sys/dev/raid/mfi/mfi_disk.c @@ -22,38 +22,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - */ -/*- - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Copyright 1994-2009 The FreeBSD Project. - * All rights reserved. - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfi_disk.c,v 1.8 2008/11/17 23:30:19 jhb Exp $ + * FreeBSD projects/head_mfi/ r232888 */ #include "opt_mfi.h" @@ -281,7 +252,7 @@ mfi_disk_strategy(struct dev_strategy_args *ap) struct bio *bio = ap->a_bio; struct buf *bp = bio->bio_buf; struct mfi_disk *sc = ap->a_head.a_dev->si_drv1; - struct mfi_softc *controller; + struct mfi_softc *controller = sc->ld_controller; if (sc == NULL) { bp->b_error = EINVAL; @@ -291,6 +262,16 @@ mfi_disk_strategy(struct dev_strategy_args *ap) return (0); } + if (controller->hw_crit_error) { + bp->b_error = EBUSY; + return (0); + } + + if (controller->issuepend_done == 0) { + bp->b_error = EBUSY; + return (0); + } + /* * XXX swildner * @@ -310,7 +291,6 @@ mfi_disk_strategy(struct dev_strategy_args *ap) return (0); } - controller = sc->ld_controller; bio->bio_driver_info = sc; lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE); mfi_enqueue_bio(controller, bio); diff --git a/sys/dev/raid/mfi/mfi_ioctl.h b/sys/dev/raid/mfi/mfi_ioctl.h index 8450495493..15eea40ce8 100644 --- a/sys/dev/raid/mfi/mfi_ioctl.h +++ b/sys/dev/raid/mfi/mfi_ioctl.h @@ -24,18 +24,25 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/dev/mfi/mfi_ioctl.h,v 1.9 2009/08/13 23:18:45 scottl Exp $ + * FreeBSD projects/head_mfi/ r227612 */ #include +#include + #include -#if defined(__x86_64__) /* Assume amd64 wants 32 bit Linux */ struct iovec32 { u_int32_t iov_base; int iov_len; }; -#endif + +struct megasas_sge +{ + bus_addr_t phys_addr; + uint32_t length; +}; #define MFIQ_FREE 0 #define MFIQ_BIO 1 @@ -80,23 +87,6 @@ struct mfi_ioc_packet { struct iovec mfi_sgl[MAX_IOCTL_SGE]; } __packed; -#ifdef __x86_64__ -struct mfi_ioc_packet32 { - uint16_t mfi_adapter_no; - uint16_t mfi_pad1; - uint32_t mfi_sgl_off; - uint32_t mfi_sge_count; - uint32_t mfi_sense_off; - uint32_t mfi_sense_len; - union { - uint8_t raw[128]; - struct mfi_frame_header hdr; - } mfi_frame; - - struct iovec32 mfi_sgl[MAX_IOCTL_SGE]; -} __packed; -#endif - struct mfi_ioc_aen { uint16_t aen_adapter_no; uint16_t aen_pad1; @@ -105,9 +95,6 @@ struct mfi_ioc_aen { } __packed; #define MFI_CMD _IOWR('M', 1, struct mfi_ioc_packet) -#ifdef __x86_64__ -#define MFI_CMD32 _IOWR('M', 1, struct mfi_ioc_packet32) -#endif #define MFI_SET_AEN _IOW('M', 3, struct mfi_ioc_aen) #define MAX_LINUX_IOCTL_SGE 16 @@ -137,19 +124,8 @@ struct mfi_ioc_passthru { uint8_t *buf; } __packed; -#ifdef __x86_64__ -struct mfi_ioc_passthru32 { - struct mfi_dcmd_frame ioc_frame; - uint32_t buf_size; - uint32_t buf; -} __packed; -#endif - #define MFIIO_STATS _IOWR('Q', 101, union mfi_statrequest) #define MFIIO_PASSTHRU _IOWR('C', 102, struct mfi_ioc_passthru) -#ifdef __x86_64__ -#define MFIIO_PASSTHRU32 _IOWR('C', 102, struct mfi_ioc_passthru32) -#endif struct mfi_linux_ioc_aen { uint16_t laen_adapter_no; diff --git a/sys/dev/raid/mfi/mfi_pci.c b/sys/dev/raid/mfi/mfi_pci.c index cb3163d6b3..629537e7fc 100644 --- a/sys/dev/raid/mfi/mfi_pci.c +++ b/sys/dev/raid/mfi/mfi_pci.c @@ -48,38 +48,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - */ -/*- - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Copyright 1994-2009 The FreeBSD Project. - * All rights reserved. - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfi_pci.c,v 1.16 2010/03/02 17:34:11 kib Exp $ + * FreeBSD projects/head_mfi/ r232888 */ /* PCI/PCI-X/PCIe bus interface for the LSI MegaSAS controllers */ @@ -96,7 +67,6 @@ #include #include #include - #include #include @@ -134,6 +104,9 @@ static devclass_t mfi_devclass; DRIVER_MODULE(mfi, pci, mfi_pci_driver, mfi_devclass, NULL, NULL); MODULE_VERSION(mfi, 1); +static int mfi_msi_enable = 1; +TUNABLE_INT("hw.mfi.msi.enable", &mfi_msi_enable); + struct mfi_ident { uint16_t vendor; uint16_t device; @@ -142,6 +115,17 @@ struct mfi_ident { int flags; const char *desc; } mfi_identifiers[] = { + {0x1000, 0x005b, 0x1028, 0x1f2d, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H810 Adapter"}, + {0x1000, 0x005b, 0x1028, 0x1f30, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710 Embedded"}, + {0x1000, 0x005b, 0x1028, 0x1f31, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710P Adapter"}, + {0x1000, 0x005b, 0x1028, 0x1f33, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710P Mini (blades)"}, + {0x1000, 0x005b, 0x1028, 0x1f34, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710P Mini (monolithics)"}, + {0x1000, 0x005b, 0x1028, 0x1f35, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710 Adapter"}, + {0x1000, 0x005b, 0x1028, 0x1f37, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710 Mini (blades)"}, + {0x1000, 0x005b, 0x1028, 0x1f38, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710 Mini (monolithics)"}, + {0x1000, 0x005b, 0x8086, 0x9265, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Intel (R) RAID Controller RS25DB080"}, + {0x1000, 0x005b, 0x8086, 0x9285, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Intel (R) RAID Controller RS25NB008"}, + {0x1000, 0x005b, 0xffff, 0xffff, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "ThunderBolt"}, {0x1000, 0x0060, 0x1028, 0xffff, MFI_FLAGS_1078, "Dell PERC 6"}, {0x1000, 0x0060, 0xffff, 0xffff, MFI_FLAGS_1078, "LSI MegaSAS 1078"}, {0x1000, 0x0071, 0xffff, 0xffff, MFI_FLAGS_SKINNY, "Drake Skinny"}, @@ -200,6 +184,7 @@ mfi_pci_attach(device_t dev) struct mfi_ident *m; uint32_t command; int error; + u_int irq_flags; sc = device_get_softc(dev); bzero(sc, sizeof(*sc)); @@ -227,7 +212,8 @@ mfi_pci_attach(device_t dev) /* 1068/1078: Memory mapped BAR is at offset 0x10 */ sc->mfi_regs_rid = PCIR_BAR(0); } else if ((sc->mfi_flags & MFI_FLAGS_GEN2) || - (sc->mfi_flags & MFI_FLAGS_SKINNY)) { + (sc->mfi_flags & MFI_FLAGS_SKINNY) || + (sc->mfi_flags & MFI_FLAGS_TBOLT)) { /* GEN2/Skinny: Memory mapped BAR is at offset 0x14 */ sc->mfi_regs_rid = PCIR_BAR(1); } @@ -256,6 +242,16 @@ mfi_pci_attach(device_t dev) goto out; } + /* Allocate IRQ resource. */ + sc->mfi_irq_rid = 0; + sc->mfi_irq_type = pci_alloc_1intr(sc->mfi_dev, mfi_msi_enable, + &sc->mfi_irq_rid, &irq_flags); + if ((sc->mfi_irq = bus_alloc_resource_any(sc->mfi_dev, SYS_RES_IRQ, + &sc->mfi_irq_rid, irq_flags)) == NULL) { + device_printf(sc->mfi_dev, "Cannot allocate interrupt\n"); + return (EINVAL); + } + error = mfi_attach(sc); out: if (error) { @@ -270,9 +266,8 @@ static int mfi_pci_detach(device_t dev) { struct mfi_softc *sc; - struct mfi_disk *ld; - struct mfi_system_pd *syspd = NULL; - int error; + device_t *devlist; + int error, devcount, i; sc = device_get_softc(dev); @@ -286,20 +281,13 @@ mfi_pci_detach(device_t dev) sc->mfi_detaching = 1; lockmgr(&sc->mfi_io_lock, LK_RELEASE); - while ((ld = TAILQ_FIRST(&sc->mfi_ld_tqh)) != NULL) { - if ((error = device_delete_child(dev, ld->ld_dev)) != 0) { - sc->mfi_detaching = 0; - lockmgr(&sc->mfi_config_lock, LK_RELEASE); - return (error); - } - } - while ((syspd = TAILQ_FIRST(&sc->mfi_syspd_tqh)) != NULL) { - if ((error = device_delete_child(dev,syspd->pd_dev)) != 0) { - sc->mfi_detaching = 0; - lockmgr(&sc->mfi_config_lock, LK_RELEASE); - return (error); - } + if ((error = device_get_children(sc->mfi_dev, &devlist, &devcount)) != 0) { + lockmgr(&sc->mfi_config_lock, LK_RELEASE); + return error; } + for (i = 0; i < devcount; i++) + device_delete_child(sc->mfi_dev, devlist[i]); + kfree(devlist, M_TEMP); lockmgr(&sc->mfi_config_lock, LK_RELEASE); EVENTHANDLER_DEREGISTER(shutdown_final, sc->mfi_eh); @@ -318,8 +306,8 @@ mfi_pci_free(struct mfi_softc *sc) bus_release_resource(sc->mfi_dev, SYS_RES_MEMORY, sc->mfi_regs_rid, sc->mfi_regs_resource); } - - return; + if (sc->mfi_irq_type == PCI_INTR_TYPE_MSI) + pci_release_msi(sc->mfi_dev); } static int diff --git a/sys/dev/raid/mfi/mfi_syspd.c b/sys/dev/raid/mfi/mfi_syspd.c index b929de126b..f56a80335e 100644 --- a/sys/dev/raid/mfi/mfi_syspd.c +++ b/sys/dev/raid/mfi/mfi_syspd.c @@ -29,6 +29,7 @@ * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfi_pddisk.c,v 1.2.2.6 2007/08/24 17:29:18 jhb Exp $ + * FreeBSD projects/head_mfi/ r232888 */ #include "opt_mfi.h" @@ -212,7 +213,8 @@ mfi_syspd_disable(struct mfi_system_pd *sc) if (sc->pd_flags & MFI_DISK_FLAGS_OPEN) { if (sc->pd_controller->mfi_delete_busy_volumes) return (0); - device_printf(sc->pd_dev, "Unable to delete busy syspd device\n"); + device_printf(sc->pd_dev, + "Unable to delete busy syspd device\n"); return (EBUSY); } sc->pd_flags |= MFI_DISK_FLAGS_DISABLED; @@ -233,7 +235,7 @@ mfi_syspd_strategy(struct dev_strategy_args *ap) struct bio *bio = ap->a_bio; struct buf *bp = bio->bio_buf; struct mfi_system_pd *sc = ap->a_head.a_dev->si_drv1; - struct mfi_softc *controller; + struct mfi_softc *controller = sc->pd_controller; if (sc == NULL) { bp->b_error = EINVAL; @@ -243,6 +245,16 @@ mfi_syspd_strategy(struct dev_strategy_args *ap) return (0); } + if (controller->hw_crit_error) { + bp->b_error = EBUSY; + return (0); + } + + if (controller->issuepend_done == 0) { + bp->b_error = EBUSY; + return (0); + } + /* * XXX swildner * @@ -262,7 +274,6 @@ mfi_syspd_strategy(struct dev_strategy_args *ap) return (0); } - controller = sc->pd_controller; bio->bio_driver_info = sc; lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE); mfi_enqueue_bio(controller, bio); @@ -272,26 +283,6 @@ mfi_syspd_strategy(struct dev_strategy_args *ap) return (0); } -#if 0 -void -mfi_disk_complete(struct bio *bio) -{ - struct mfi_system_pd *sc = bio->bio_driver_info; - struct buf *bp = bio->bio_buf; - - devstat_end_transaction_buf(&sc->pd_devstat, bp); - if (bio->b_flags & B_ERROR) { - if (bp->b_error == 0) - bp->b_error = EIO; - diskerr(bio, sc->pd_disk.d_cdev, "hard error", -1, 1); - kprintf("\n"); - } else { - bp->b_resid = 0; - } - biodone(bio); -} -#endif - static int mfi_syspd_dump(struct dev_dump_args *ap) { @@ -307,8 +298,8 @@ mfi_syspd_dump(struct dev_dump_args *ap) parent_sc = sc->pd_controller; if (len > 0) { - if ((error = mfi_dump_syspd_blocks(parent_sc, sc->pd_id, offset / - MFI_SECTOR_LEN, virt, len)) != 0) + if ((error = mfi_dump_syspd_blocks(parent_sc, + sc->pd_id, offset / MFI_SECTOR_LEN, virt, len)) != 0) return (error); } else { /* mfi_sync_cache(parent_sc, sc->ld_id); */ diff --git a/sys/dev/raid/mfi/mfi_tbolt.c b/sys/dev/raid/mfi/mfi_tbolt.c new file mode 100644 index 0000000000..551a648caf --- /dev/null +++ b/sys/dev/raid/mfi/mfi_tbolt.c @@ -0,0 +1,1342 @@ +/*- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Copyright 1994-2009 The FreeBSD Project. + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * $FreeBSD: src/sys/dev/mfi/mfi_tbolt.c,v 1.00 2010/06/30 16:00:00 Bharat Gusain Exp $ + * FreeBSD projects/head_mfi/ r232949 + */ + +#include "opt_mfi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct mfi_cmd_tbolt *mfi_tbolt_get_cmd(struct mfi_softc *sc); +union mfi_mpi2_request_descriptor * +mfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index); +void mfi_tbolt_complete_cmd(struct mfi_softc *sc); +int mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd, + struct mfi_cmd_tbolt *cmd); +static inline void mfi_tbolt_return_cmd(struct mfi_softc *sc, + struct mfi_cmd_tbolt *cmd); +union mfi_mpi2_request_descriptor *mfi_tbolt_build_mpt_cmd(struct mfi_softc + *sc, struct mfi_command *cmd); +uint8_t +mfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd); +union mfi_mpi2_request_descriptor *mfi_build_and_issue_cmd(struct mfi_softc + *sc, struct mfi_command *mfi_cmd); +int mfi_tbolt_is_ldio(struct mfi_command *mfi_cmd); +void mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd, + struct mfi_cmd_tbolt *cmd); +static int mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command + *mfi_cmd, pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd); +static int mfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command + *mfi_cmd, uint8_t *cdb); +void +map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status, + uint8_t ext_status); +static void mfi_issue_pending_cmds_again (struct mfi_softc *sc); +static void mfi_kill_hba (struct mfi_softc *sc); +static void mfi_process_fw_state_chg_isr(void *arg); +uint8_t mfi_tbolt_get_map_info(struct mfi_softc *sc); + +#define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000008) + +void +mfi_tbolt_enable_intr_ppc(struct mfi_softc *sc) +{ + MFI_WRITE4(sc, MFI_OMSK, ~MFI_FUSION_ENABLE_INTERRUPT_MASK); + MFI_READ4(sc, MFI_OMSK); +} + +void +mfi_tbolt_disable_intr_ppc(struct mfi_softc *sc) +{ + MFI_WRITE4(sc, MFI_OMSK, 0xFFFFFFFF); + MFI_READ4(sc, MFI_OMSK); +} + +int32_t +mfi_tbolt_read_fw_status_ppc(struct mfi_softc *sc) +{ + return MFI_READ4(sc, MFI_OSP0); +} + +int32_t +mfi_tbolt_check_clear_intr_ppc(struct mfi_softc *sc) +{ + int32_t status, mfi_status = 0; + + status = MFI_READ4(sc, MFI_OSTS); + + if (status & 1) { + MFI_WRITE4(sc, MFI_OSTS, status); + MFI_READ4(sc, MFI_OSTS); + if (status & MFI_STATE_CHANGE_INTERRUPT) { + mfi_status |= MFI_FIRMWARE_STATE_CHANGE; + } + + return mfi_status; + } + if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK)) + return 1; + + MFI_READ4(sc, MFI_OSTS); + return 0; +} + + +void +mfi_tbolt_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, + uint32_t frame_cnt) +{ + bus_add |= (MFI_REQ_DESCRIPT_FLAGS_MFA + << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + MFI_WRITE4(sc, MFI_IQPL, (uint32_t)bus_add); + MFI_WRITE4(sc, MFI_IQPH, (uint32_t)((uint64_t)bus_add >> 32)); +} + +/** + * mfi_tbolt_adp_reset - For controller reset + * @regs: MFI register set + */ +int mfi_tbolt_adp_reset(struct mfi_softc *sc) +{ + int retry = 0, i = 0; + int HostDiag; + + MFI_WRITE4(sc, MFI_WSR, 0xF); + MFI_WRITE4(sc, MFI_WSR, 4); + MFI_WRITE4(sc, MFI_WSR, 0xB); + MFI_WRITE4(sc, MFI_WSR, 2); + MFI_WRITE4(sc, MFI_WSR, 7); + MFI_WRITE4(sc, MFI_WSR, 0xD); + + for (i = 0; i < 10000; i++) ; + + HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR); + + while (!( HostDiag & DIAG_WRITE_ENABLE)) { + for (i = 0; i < 1000; i++); + HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR); + device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%x, " + "hostdiag=%x\n", retry, HostDiag); + + if (retry++ >= 100) + return 1; + } + + device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: HostDiag=%x\n", HostDiag); + + MFI_WRITE4(sc, MFI_HDR, (HostDiag | DIAG_RESET_ADAPTER)); + + for (i=0; i < 10; i++) { + for (i = 0; i < 10000; i++); + } + + HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR); + while (HostDiag & DIAG_RESET_ADAPTER) { + for (i = 0; i < 1000; i++) ; + HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR); + device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%x, " + "hostdiag=%x\n", retry, HostDiag); + + if (retry++ >= 1000) + return 1; + } + return 0; +} + +/* + ******************************************************************************************* + * Description: + * This routine initialize Thunderbolt specific device information + ******************************************************************************************* + */ +void mfi_tbolt_init_globals(struct mfi_softc *sc) +{ + /* Initialize single reply size and Message size */ + sc->reply_size = MEGASAS_THUNDERBOLT_REPLY_SIZE; + sc->raid_io_msg_size = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE; + + /* + * Calculating how many SGEs allowed in a allocated main message + * (size of the Message - Raid SCSI IO message size(except SGE)) + * / size of SGE + * (0x100 - (0x90 - 0x10)) / 0x10 = 8 + */ + sc->max_SGEs_in_main_message = + (uint8_t)((sc->raid_io_msg_size + - (sizeof(struct mfi_mpi2_request_raid_scsi_io) + - sizeof(MPI2_SGE_IO_UNION))) / sizeof(MPI2_SGE_IO_UNION)); + /* + * (Command frame size allocaed in SRB ext - Raid SCSI IO message size) + * / size of SGL ; + * (1280 - 256) / 16 = 64 + */ + sc->max_SGEs_in_chain_message = (MR_COMMAND_SIZE + - sc->raid_io_msg_size) / sizeof(MPI2_SGE_IO_UNION); + /* + * (0x08-1) + 0x40 = 0x47 - 0x01 = 0x46 one is left for command + * colscing + */ + sc->mfi_max_sge = (sc->max_SGEs_in_main_message - 1) + + sc->max_SGEs_in_chain_message - 1; + /* + * This is the offset in number of 4 * 32bit words to the next chain + * (0x100 - 0x10)/0x10 = 0xF(15) + */ + sc->chain_offset_value_for_main_message = (sc->raid_io_msg_size + - sizeof(MPI2_SGE_IO_UNION))/16; + sc->chain_offset_value_for_mpt_ptmsg + = offsetof(struct mfi_mpi2_request_raid_scsi_io, SGL)/16; + sc->mfi_cmd_pool_tbolt = NULL; + sc->request_desc_pool = NULL; +} + +/* + **************************************************************************** + * Description: + * This function calculates the memory requirement for Thunderbolt + * controller + * Return Value: + * Total required memory in bytes + **************************************************************************** + */ + +uint32_t mfi_tbolt_get_memory_requirement(struct mfi_softc *sc) +{ + uint32_t size; + + size = MEGASAS_THUNDERBOLT_MSG_ALLIGNMENT; /* for Alignment */ + size += sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1); + size += sc->reply_size * sc->mfi_max_fw_cmds; + /* this is for SGL's */ + size += MEGASAS_MAX_SZ_CHAIN_FRAME * sc->mfi_max_fw_cmds; + return size; +} + +/* + **************************************************************************** + * Description: + * This function will prepare message pools for the Thunderbolt controller + * Arguments: + * DevExt - HBA miniport driver's adapter data storage structure + * pMemLocation - start of the memory allocated for Thunderbolt. + * Return Value: + * TRUE if successful + * FALSE if failed + **************************************************************************** + */ +int mfi_tbolt_init_desc_pool(struct mfi_softc *sc, uint8_t* mem_location, + uint32_t tbolt_contg_length) +{ + uint32_t offset = 0; + uint8_t *addr = mem_location; + + /* Request Descriptor Base physical Address */ + + /* For Request Decriptors Virtual Memory */ + /* Initialise the aligned IO Frames Virtual Memory Pointer */ + if (((uintptr_t)addr) & (0xFF)) { + addr = &addr[sc->raid_io_msg_size]; + addr = (uint8_t *)((uintptr_t)addr & (~0xFF)); + sc->request_message_pool_align = addr; + } else + sc->request_message_pool_align = addr; + + offset = sc->request_message_pool_align - sc->request_message_pool; + sc->request_msg_busaddr = sc->mfi_tb_busaddr + offset; + + /* DJA XXX should this be bus dma ??? */ + /* Skip request message pool */ + addr = &addr[sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1)]; + /* Reply Frame Pool is initialized */ + sc->reply_frame_pool = (struct mfi_mpi2_reply_header *) addr; + if (((uintptr_t)addr) & (0xFF)) { + addr = &addr[sc->reply_size]; + addr = (uint8_t *)((uintptr_t)addr & (~0xFF)); + } + sc->reply_frame_pool_align + = (struct mfi_mpi2_reply_header *)addr; + + offset = (uintptr_t)sc->reply_frame_pool_align + - (uintptr_t)sc->request_message_pool; + sc->reply_frame_busaddr = sc->mfi_tb_busaddr + offset; + + /* Skip Reply Frame Pool */ + addr += sc->reply_size * sc->mfi_max_fw_cmds; + sc->reply_pool_limit = addr; + + /* initializing reply address to 0xFFFFFFFF */ + memset((uint8_t *)sc->reply_frame_pool, 0xFF, + (sc->reply_size * sc->mfi_max_fw_cmds)); + + offset = sc->reply_size * sc->mfi_max_fw_cmds; + sc->sg_frame_busaddr = sc->reply_frame_busaddr + offset; + /* initialize the last_reply_idx to 0 */ + sc->last_reply_idx = 0; + offset = (sc->sg_frame_busaddr + (MEGASAS_MAX_SZ_CHAIN_FRAME * + sc->mfi_max_fw_cmds)) - sc->mfi_tb_busaddr; + if (offset > tbolt_contg_length) + device_printf(sc->mfi_dev, "Error:Initialized more than " + "allocated\n"); + return 0; +} + +/* + **************************************************************************** + * Description: + * This routine prepare and issue INIT2 frame to the Firmware + **************************************************************************** + */ + +int +mfi_tbolt_init_MFI_queue(struct mfi_softc *sc) +{ + struct MPI2_IOC_INIT_REQUEST *mpi2IocInit; + struct mfi_init_frame *mfi_init; + uintptr_t offset = 0; + bus_addr_t phyAddress; + MFI_ADDRESS *mfiAddressTemp; + struct mfi_command *cm; + int error; + + mpi2IocInit = (struct MPI2_IOC_INIT_REQUEST *)sc->mfi_tb_ioc_init_desc; + /* Check if initialization is already completed */ + if (sc->MFA_enabled) { + return 1; + } + + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); + if ((cm = mfi_dequeue_free(sc)) == NULL) { + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + return (EBUSY); + } + cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_tb_init); + cm->cm_frame_busaddr = sc->mfi_tb_init_busaddr; + cm->cm_dmamap = sc->mfi_tb_init_dmamap; + cm->cm_frame->header.context = 0; + cm->cm_sc = sc; + cm->cm_index = 0; + + /* + * Abuse the SG list area of the frame to hold the init_qinfo + * object; + */ + mfi_init = &cm->cm_frame->init; + + bzero(mpi2IocInit, sizeof(struct MPI2_IOC_INIT_REQUEST)); + mpi2IocInit->Function = MPI2_FUNCTION_IOC_INIT; + mpi2IocInit->WhoInit = MPI2_WHOINIT_HOST_DRIVER; + + /* set MsgVersion and HeaderVersion host driver was built with */ + mpi2IocInit->MsgVersion = MPI2_VERSION; + mpi2IocInit->HeaderVersion = MPI2_HEADER_VERSION; + mpi2IocInit->SystemRequestFrameSize = sc->raid_io_msg_size/4; + mpi2IocInit->ReplyDescriptorPostQueueDepth + = (uint16_t)sc->mfi_max_fw_cmds; + mpi2IocInit->ReplyFreeQueueDepth = 0; /* Not supported by MR. */ + + /* Get physical address of reply frame pool */ + offset = (uintptr_t) sc->reply_frame_pool_align + - (uintptr_t)sc->request_message_pool; + phyAddress = sc->mfi_tb_busaddr + offset; + mfiAddressTemp = + (MFI_ADDRESS *)&mpi2IocInit->ReplyDescriptorPostQueueAddress; + mfiAddressTemp->u.addressLow = (uint32_t)phyAddress; + mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32); + + /* Get physical address of request message pool */ + offset = sc->request_message_pool_align - sc->request_message_pool; + phyAddress = sc->mfi_tb_busaddr + offset; + mfiAddressTemp = (MFI_ADDRESS *)&mpi2IocInit->SystemRequestFrameBaseAddress; + mfiAddressTemp->u.addressLow = (uint32_t)phyAddress; + mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32); + mpi2IocInit->ReplyFreeQueueAddress = 0; /* Not supported by MR. */ + mpi2IocInit->TimeStamp = time_second; + + if (sc->verbuf) { + ksnprintf((char *)sc->verbuf, strlen(MEGASAS_VERSION) + 2, "%s\n", + MEGASAS_VERSION); + mfi_init->driver_ver_lo = (uint32_t)sc->verbuf_h_busaddr; + mfi_init->driver_ver_hi = + (uint32_t)((uint64_t)sc->verbuf_h_busaddr >> 32); + } + /* Get the physical address of the mpi2 ioc init command */ + phyAddress = sc->mfi_tb_ioc_init_busaddr; + mfi_init->qinfo_new_addr_lo = (uint32_t)phyAddress; + mfi_init->qinfo_new_addr_hi = (uint32_t)((uint64_t)phyAddress >> 32); + mfi_init->header.flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; + + mfi_init->header.cmd = MFI_CMD_INIT; + mfi_init->header.data_len = sizeof(struct MPI2_IOC_INIT_REQUEST); + mfi_init->header.cmd_status = MFI_STAT_INVALID_STATUS; + + cm->cm_data = NULL; + cm->cm_flags |= MFI_CMD_POLLED; + cm->cm_timestamp = time_second; + if ((error = mfi_mapcmd(sc, cm)) != 0) { + device_printf(sc->mfi_dev, "failed to send IOC init2 " + "command %d at %lx\n", error, (long)cm->cm_frame_busaddr); + mfi_release_command(cm); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + return (error); + } + mfi_release_command(cm); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + + if (mfi_init->header.cmd_status == 0) { + sc->MFA_enabled = 1; + } + else { + device_printf(sc->mfi_dev, "Init command Failed %x\n", + mfi_init->header.cmd_status); + return 1; + } + + return 0; + +} + +int mfi_tbolt_alloc_cmd(struct mfi_softc *sc) +{ + struct mfi_cmd_tbolt *cmd; + bus_addr_t io_req_base_phys; + uint8_t *io_req_base; + int i = 0, j = 0, offset = 0; + + /* + * sc->mfi_cmd_pool_tbolt is an array of struct mfi_cmd_tbolt pointers. + * Allocate the dynamic array first and then allocate individual + * commands. + */ + sc->request_desc_pool = kmalloc(sizeof( + union mfi_mpi2_request_descriptor) * sc->mfi_max_fw_cmds, + M_MFIBUF, M_NOWAIT|M_ZERO); + sc->mfi_cmd_pool_tbolt = kmalloc(sizeof(struct mfi_cmd_tbolt*) + * sc->mfi_max_fw_cmds, M_MFIBUF, M_NOWAIT|M_ZERO); + + if (!sc->mfi_cmd_pool_tbolt) { + device_printf(sc->mfi_dev, "out of memory. Could not alloc " + "memory for cmd_list_fusion\n"); + return 1; + } + + for (i = 0; i < sc->mfi_max_fw_cmds; i++) { + sc->mfi_cmd_pool_tbolt[i] = kmalloc(sizeof( + struct mfi_cmd_tbolt),M_MFIBUF, M_NOWAIT|M_ZERO); + + if (!sc->mfi_cmd_pool_tbolt[i]) { + device_printf(sc->mfi_dev, "Could not alloc cmd list " + "fusion\n"); + + for (j = 0; j < i; j++) + kfree(sc->mfi_cmd_pool_tbolt[j], M_MFIBUF); + + kfree(sc->mfi_cmd_pool_tbolt, M_MFIBUF); + sc->mfi_cmd_pool_tbolt = NULL; + } + } + + /* + * The first 256 bytes (SMID 0) is not used. Don't add to the cmd + *list + */ + io_req_base = sc->request_message_pool_align + + MEGASAS_THUNDERBOLT_NEW_MSG_SIZE; + io_req_base_phys = sc->request_msg_busaddr + + MEGASAS_THUNDERBOLT_NEW_MSG_SIZE; + + /* + * Add all the commands to command pool (instance->cmd_pool) + */ + /* SMID 0 is reserved. Set SMID/index from 1 */ + + for (i = 0; i < sc->mfi_max_fw_cmds; i++) { + cmd = sc->mfi_cmd_pool_tbolt[i]; + offset = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * i; + cmd->index = i + 1; + cmd->request_desc = (union mfi_mpi2_request_descriptor *) + (sc->request_desc_pool + i); + cmd->io_request = (struct mfi_mpi2_request_raid_scsi_io *) + (io_req_base + offset); + cmd->io_request_phys_addr = io_req_base_phys + offset; + cmd->sg_frame = (MPI2_SGE_IO_UNION *)(sc->reply_pool_limit + + i * MEGASAS_MAX_SZ_CHAIN_FRAME); + cmd->sg_frame_phys_addr = sc->sg_frame_busaddr + i + * MEGASAS_MAX_SZ_CHAIN_FRAME; + + TAILQ_INSERT_TAIL(&(sc->mfi_cmd_tbolt_tqh), cmd, next); + } + return 0; +} + +int mfi_tbolt_reset(struct mfi_softc *sc) +{ + uint32_t fw_state; + + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); + if (atomic_read(&sc->fw_reset_no_pci_access)) { + device_printf(sc->mfi_dev, "NO PCI ACCESS\n"); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + return 1; + } + + if (sc->hw_crit_error) { + device_printf(sc->mfi_dev, "HW CRITICAL ERROR\n"); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + return 1; + } + + if (sc->mfi_flags & MFI_FLAGS_TBOLT) { + fw_state = sc->mfi_read_fw_status(sc); + if ((fw_state & MFI_FWSTATE_FAULT) == MFI_FWSTATE_FAULT) { + if ((sc->disableOnlineCtrlReset == 0) + && (sc->adpreset == 0)) { + device_printf(sc->mfi_dev, "Adapter RESET " + "condition is detected\n"); + sc->adpreset = 1; + sc->issuepend_done = 0; + sc->MFA_enabled = 0; + sc->last_reply_idx = 0; + mfi_process_fw_state_chg_isr((void *) sc); + } + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + return 0; + } + } + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + return 1; +} + +/* + * mfi_intr_tbolt - isr entry point + */ +void mfi_intr_tbolt(void *arg) +{ + struct mfi_softc *sc = (struct mfi_softc *)arg; + + if (sc->mfi_check_clear_intr(sc) == 1) { + return; + } + if (sc->mfi_detaching) + return; + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); + mfi_tbolt_complete_cmd(sc); + if (sc->mfi_flags & MFI_FLAGS_QFRZN) + sc->mfi_flags &= ~MFI_FLAGS_QFRZN; + mfi_startio(sc); + lockmgr(&sc->mfi_io_lock, LK_RELEASE); + return; +} + +/** + * map_cmd_status - Maps FW cmd status to OS cmd status + * @cmd : Pointer to cmd + * @status : status of cmd returned by FW + * @ext_status : ext status of cmd returned by FW + */ + +void +map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status, + uint8_t ext_status) +{ + + switch (status) { + + case MFI_STAT_OK: + mfi_cmd->cm_frame->header.cmd_status = 0; + mfi_cmd->cm_frame->dcmd.header.cmd_status = 0; + break; + + case MFI_STAT_SCSI_IO_FAILED: + case MFI_STAT_LD_INIT_IN_PROGRESS: + mfi_cmd->cm_frame->header.cmd_status = status; + mfi_cmd->cm_frame->header.scsi_status = ext_status; + mfi_cmd->cm_frame->dcmd.header.cmd_status = status; + mfi_cmd->cm_frame->dcmd.header.scsi_status + = ext_status; + break; + + case MFI_STAT_SCSI_DONE_WITH_ERROR: + mfi_cmd->cm_frame->header.cmd_status = ext_status; + mfi_cmd->cm_frame->dcmd.header.cmd_status = ext_status; + break; + + case MFI_STAT_LD_OFFLINE: + case MFI_STAT_DEVICE_NOT_FOUND: + mfi_cmd->cm_frame->header.cmd_status = status; + mfi_cmd->cm_frame->dcmd.header.cmd_status = status; + break; + + default: + mfi_cmd->cm_frame->header.cmd_status = status; + mfi_cmd->cm_frame->dcmd.header.cmd_status = status; + break; + } +} + +/** + * mfi_tbolt_return_cmd - Return a cmd to free command pool + * @instance: Adapter soft state + * @cmd: Command packet to be returned to free command pool + */ +static inline void +mfi_tbolt_return_cmd(struct mfi_softc *sc, struct mfi_cmd_tbolt *cmd) +{ + KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); + + TAILQ_INSERT_TAIL(&sc->mfi_cmd_tbolt_tqh, cmd, next); +} + +void mfi_tbolt_complete_cmd(struct mfi_softc *sc) +{ + struct mfi_mpi2_reply_header *desc, *reply_desc; + struct mfi_command *cmd_mfi; /* For MFA Cmds */ + struct mfi_cmd_tbolt *cmd_tbolt; + uint16_t smid; + uint8_t reply_descript_type; + struct mfi_mpi2_request_raid_scsi_io *scsi_io_req; + uint32_t status, extStatus; + uint16_t num_completed; + union desc_value val; + + desc = (struct mfi_mpi2_reply_header *) + ((uintptr_t)sc->reply_frame_pool_align + + sc->last_reply_idx * sc->reply_size); + reply_desc = desc; + + if (!reply_desc) + device_printf(sc->mfi_dev, "reply desc is NULL!!\n"); + + reply_descript_type = reply_desc->ReplyFlags + & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) + return; + + num_completed = 0; + val.word = ((union mfi_mpi2_reply_descriptor *)desc)->words; + + /* Read Reply descriptor */ + while ((val.u.low != 0xFFFFFFFF) && (val.u.high != 0xFFFFFFFF)) { + + smid = reply_desc->SMID; + if (!smid || smid > sc->mfi_max_fw_cmds + 1) { + device_printf(sc->mfi_dev, "smid is %x. Cannot " + "proceed. Returning \n", smid); + return; + } + + cmd_tbolt = sc->mfi_cmd_pool_tbolt[smid - 1]; + cmd_mfi = &sc->mfi_commands[cmd_tbolt->sync_cmd_idx]; + scsi_io_req = cmd_tbolt->io_request; + + /* Check if internal commands */ + status = cmd_mfi->cm_frame->dcmd.header.cmd_status; + extStatus = cmd_mfi->cm_frame->dcmd.header.scsi_status; + + switch (scsi_io_req->Function) { + case MPI2_FUNCTION_LD_IO_REQUEST: + /* Regular Path IO. */ + /* Map the Fw Error Status. */ + map_tbolt_cmd_status(cmd_mfi, status, + extStatus); + if ((cmd_mfi->cm_frame->dcmd.opcode + == MFI_DCMD_LD_MAP_GET_INFO) + && (cmd_mfi->cm_frame->dcmd.mbox[1] == 1)) { + if (cmd_mfi->cm_frame->header.cmd_status + != 0) + device_printf(sc->mfi_dev, + "map sync failed\n"); + else { + sc->map_id++; + device_printf(sc->mfi_dev, + "map sync completed\n"); + mfi_release_command(cmd_mfi); + } + } + if ((cmd_mfi->cm_flags & MFI_ON_MFIQ_BUSY) + == MFI_ON_MFIQ_BUSY + && (cmd_mfi->cm_flags & MFI_CMD_POLLED) == 0) { + /* BHARAT poll workaround */ + mfi_remove_busy(cmd_mfi); + cmd_mfi->cm_error = 0; + mfi_complete(sc, cmd_mfi); + } + mfi_tbolt_return_cmd(sc, cmd_tbolt); + break; + case MPI2_FUNCTION_PASSTHRU_IO_REQUEST: + map_tbolt_cmd_status(cmd_mfi, status, extStatus); + if ((cmd_mfi->cm_frame->dcmd.opcode + == MFI_DCMD_LD_MAP_GET_INFO) + && (cmd_mfi->cm_frame->dcmd.mbox[1] == 1)) { + if (cmd_mfi->cm_frame->header.cmd_status != 0) + device_printf(sc->mfi_dev, + "map sync failed\n"); + else { + sc->map_id++; + device_printf(sc->mfi_dev, + "map sync completed\n"); + mfi_release_command(cmd_mfi); + } + } + if ((cmd_mfi->cm_flags & MFI_ON_MFIQ_BUSY) + == MFI_ON_MFIQ_BUSY + && (cmd_mfi->cm_flags & MFI_CMD_POLLED) == 0) { + /* BHARAT poll workaround */ + mfi_remove_busy(cmd_mfi); + cmd_mfi->cm_error = 0; + mfi_complete(sc, cmd_mfi); + } + mfi_tbolt_return_cmd(sc, cmd_tbolt); + break; + } + + sc->last_reply_idx++; + if (sc->last_reply_idx >= sc->mfi_max_fw_cmds) { + MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx); + sc->last_reply_idx = 0; + } + /*set it back to all 0xfff.*/ + ((union mfi_mpi2_reply_descriptor*)desc)->words = + ~((uint64_t)0x00); + + num_completed++; + + /* Get the next reply descriptor */ + desc = (struct mfi_mpi2_reply_header *) + ((uintptr_t)sc->reply_frame_pool_align + + sc->last_reply_idx * sc->reply_size); + reply_desc = desc; + val.word = ((union mfi_mpi2_reply_descriptor*)desc)->words; + reply_descript_type = reply_desc->ReplyFlags + & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) + break; + } + + if (!num_completed) + return; + + /* update replyIndex to FW */ + if (sc->last_reply_idx) + MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx); + + return; +} + +/** + * mfi_get_cmd - Get a command from the free pool + * @instance: Adapter soft state + * + * Returns a free command from the pool + */ + +struct mfi_cmd_tbolt *mfi_tbolt_get_cmd(struct mfi_softc + *sc) +{ + struct mfi_cmd_tbolt *cmd = NULL; + + KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); + + cmd = TAILQ_FIRST(&sc->mfi_cmd_tbolt_tqh); + TAILQ_REMOVE(&sc->mfi_cmd_tbolt_tqh, cmd, next); + memset((uint8_t *)cmd->sg_frame, 0, MEGASAS_MAX_SZ_CHAIN_FRAME); + memset((uint8_t *)cmd->io_request, 0, + MEGASAS_THUNDERBOLT_NEW_MSG_SIZE); + return cmd; +} + +union mfi_mpi2_request_descriptor * +mfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index) +{ + uint8_t *p; + + if (index >= sc->mfi_max_fw_cmds) { + device_printf(sc->mfi_dev, "Invalid SMID (0x%x)request " + "for descriptor\n", index); + return NULL; + } + p = sc->request_desc_pool + sizeof(union mfi_mpi2_request_descriptor) + * index; + memset(p, 0, sizeof(union mfi_mpi2_request_descriptor)); + return (union mfi_mpi2_request_descriptor *)p; +} + + +/* Used to build IOCTL cmd */ +uint8_t +mfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd) +{ + MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain; + struct mfi_mpi2_request_raid_scsi_io *io_req; + struct mfi_cmd_tbolt *cmd; + + cmd = mfi_tbolt_get_cmd(sc); + if (!cmd) + return EBUSY; + mfi_cmd->cm_extra_frames = cmd->index; /* Frame count used as SMID */ + cmd->sync_cmd_idx = mfi_cmd->cm_index; + io_req = cmd->io_request; + mpi25_ieee_chain = (MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain; + + io_req->Function = MPI2_FUNCTION_PASSTHRU_IO_REQUEST; + io_req->SGLOffset0 = offsetof(struct mfi_mpi2_request_raid_scsi_io, + SGL) / 4; + io_req->ChainOffset = sc->chain_offset_value_for_mpt_ptmsg; + + mpi25_ieee_chain->Address = mfi_cmd->cm_frame_busaddr; + + /* + In MFI pass thru, nextChainOffset will always be zero to + indicate the end of the chain. + */ + mpi25_ieee_chain->Flags= MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT + | MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; + + /* setting the length to the maximum length */ + mpi25_ieee_chain->Length = 1024; + + return 0; +} + +void +mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd, + struct mfi_cmd_tbolt *cmd) +{ + uint32_t start_lba_lo = 0, start_lba_hi = 0, device_id; + struct mfi_mpi2_request_raid_scsi_io *io_request; + struct IO_REQUEST_INFO io_info; + + device_id = mfi_cmd->cm_frame->io.header.target_id; + io_request = cmd->io_request; + io_request->RaidContext.TargetID = device_id; + io_request->RaidContext.Status = 0; + io_request->RaidContext.exStatus =0; + + start_lba_lo = mfi_cmd->cm_frame->io.lba_lo; + start_lba_hi = mfi_cmd->cm_frame->io.lba_hi; + + memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO)); + io_info.ldStartBlock = ((uint64_t)start_lba_hi << 32) | start_lba_lo; + io_info.numBlocks = mfi_cmd->cm_frame->io.header.data_len; + io_info.ldTgtId = device_id; + if ((mfi_cmd->cm_frame->header.flags & MFI_FRAME_DIR_READ) == + MFI_FRAME_DIR_READ) + io_info.isRead = 1; + + io_request->RaidContext.timeoutValue + = MFI_FUSION_FP_DEFAULT_TIMEOUT; + io_request->Function = MPI2_FUNCTION_LD_IO_REQUEST; + io_request->DevHandle = device_id; + cmd->request_desc->header.RequestFlags + = (MFI_REQ_DESCRIPT_FLAGS_LD_IO + << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + if ((io_request->IoFlags == 6) && (io_info.numBlocks == 0)) + io_request->RaidContext.RegLockLength = 0x100; + io_request->DataLength = mfi_cmd->cm_frame->io.header.data_len + * MFI_SECTOR_LEN; +} + +int mfi_tbolt_is_ldio(struct mfi_command *mfi_cmd) +{ + if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_READ + || mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) + return 1; + else + return 0; +} + +int +mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd, struct mfi_cmd_tbolt *cmd) +{ + uint32_t device_id; + uint32_t sge_count; + uint8_t cdb[32], cdb_len; + + memset(cdb, 0, 32); + struct mfi_mpi2_request_raid_scsi_io *io_request = cmd->io_request; + + device_id = mfi_cmd->cm_frame->header.target_id; + + /* Have to build CDB here for TB as BSD don't have a scsi layer */ + if ((cdb_len = mfi_tbolt_build_cdb(sc, mfi_cmd, cdb)) == 1) + return 1; + + /* Just the CDB length,rest of the Flags are zero */ + io_request->IoFlags = cdb_len; + memcpy(io_request->CDB.CDB32, cdb, 32); + + if (mfi_tbolt_is_ldio(mfi_cmd)) + mfi_tbolt_build_ldio(sc, mfi_cmd , cmd); + else + return 1; + + /* + * Construct SGL + */ + sge_count = mfi_tbolt_make_sgl(sc, mfi_cmd, + (pMpi25IeeeSgeChain64_t) &io_request->SGL, cmd); + if (sge_count > sc->mfi_max_sge) { + device_printf(sc->mfi_dev, "Error. sge_count (0x%x) exceeds " + "max (0x%x) allowed\n", sge_count, sc->mfi_max_sge); + return 1; + } + io_request->RaidContext.numSGE = sge_count; + io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING; + + if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) + io_request->Control = MPI2_SCSIIO_CONTROL_WRITE; + else + io_request->Control = MPI2_SCSIIO_CONTROL_READ; + + io_request->SGLOffset0 = offsetof( + struct mfi_mpi2_request_raid_scsi_io, SGL)/4; + + io_request->SenseBufferLowAddress = mfi_cmd->cm_sense_busaddr; + io_request->SenseBufferLength = MFI_SENSE_LEN; + return 0; +} + +static int +mfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command *mfi_cmd, + uint8_t *cdb) +{ + uint32_t lba_lo, lba_hi, num_lba; + uint8_t cdb_len; + + if (mfi_cmd == NULL || cdb == NULL) + return 1; + num_lba = mfi_cmd->cm_frame->io.header.data_len; + lba_lo = mfi_cmd->cm_frame->io.lba_lo; + lba_hi = mfi_cmd->cm_frame->io.lba_hi; + + if ((num_lba <= 0xFF) && (lba_lo <= 0x1FFFFF)) { + if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) + /* Read 6 or Write 6 */ + cdb[0] = (uint8_t) (0x0A); + else + cdb[0] = (uint8_t) (0x08); + + cdb[4] = (uint8_t) num_lba; + cdb[3] = (uint8_t) (lba_lo & 0xFF); + cdb[2] = (uint8_t) (lba_lo >> 8); + cdb[1] = (uint8_t) ((lba_lo >> 16) & 0x1F); + cdb_len = 6; + } else if ((num_lba <= 0xFFFF) && (lba_lo <= 0xFFFFFFFF)) { + if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) + /* Read 10 or Write 10 */ + cdb[0] = (uint8_t) (0x2A); + else + cdb[0] = (uint8_t) (0x28); + cdb[8] = (uint8_t) (num_lba & 0xFF); + cdb[7] = (uint8_t) (num_lba >> 8); + cdb[5] = (uint8_t) (lba_lo & 0xFF); + cdb[4] = (uint8_t) (lba_lo >> 8); + cdb[3] = (uint8_t) (lba_lo >> 16); + cdb[2] = (uint8_t) (lba_lo >> 24); + cdb_len = 10; + } else if ((num_lba > 0xFFFF) && (lba_hi == 0)) { + if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) + /* Read 12 or Write 12 */ + cdb[0] = (uint8_t) (0xAA); + else + cdb[0] = (uint8_t) (0xA8); + cdb[9] = (uint8_t) (num_lba & 0xFF); + cdb[8] = (uint8_t) (num_lba >> 8); + cdb[7] = (uint8_t) (num_lba >> 16); + cdb[6] = (uint8_t) (num_lba >> 24); + cdb[5] = (uint8_t) (lba_lo & 0xFF); + cdb[4] = (uint8_t) (lba_lo >> 8); + cdb[3] = (uint8_t) (lba_lo >> 16); + cdb[2] = (uint8_t) (lba_lo >> 24); + cdb_len = 12; + } else { + if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) + cdb[0] = (uint8_t) (0x8A); + else + cdb[0] = (uint8_t) (0x88); + cdb[13] = (uint8_t) (num_lba & 0xFF); + cdb[12] = (uint8_t) (num_lba >> 8); + cdb[11] = (uint8_t) (num_lba >> 16); + cdb[10] = (uint8_t) (num_lba >> 24); + cdb[9] = (uint8_t) (lba_lo & 0xFF); + cdb[8] = (uint8_t) (lba_lo >> 8); + cdb[7] = (uint8_t) (lba_lo >> 16); + cdb[6] = (uint8_t) (lba_lo >> 24); + cdb[5] = (uint8_t) (lba_hi & 0xFF); + cdb[4] = (uint8_t) (lba_hi >> 8); + cdb[3] = (uint8_t) (lba_hi >> 16); + cdb[2] = (uint8_t) (lba_hi >> 24); + cdb_len = 16; + } + return cdb_len; +} + +static int +mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command *mfi_cmd, + pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd) +{ + uint8_t i, sg_processed, sg_to_process; + uint8_t sge_count, sge_idx; + union mfi_sgl *os_sgl; + + /* + * Return 0 if there is no data transfer + */ + if (!mfi_cmd->cm_sg || !mfi_cmd->cm_len) { + device_printf(sc->mfi_dev, "Buffer empty \n"); + return 0; + } + os_sgl = mfi_cmd->cm_sg; + sge_count = mfi_cmd->cm_frame->header.sg_count; + + if (sge_count > sc->mfi_max_sge) { + device_printf(sc->mfi_dev, "sgl ptr %p sg_cnt %d \n", + os_sgl, sge_count); + return sge_count; + } + + if (sge_count > sc->max_SGEs_in_main_message) + /* One element to store the chain info */ + sge_idx = sc->max_SGEs_in_main_message - 1; + else + sge_idx = sge_count; + + for (i = 0; i < sge_idx; i++) { + /* + * For 32bit BSD we are getting 32 bit SGL's from OS + * but FW only take 64 bit SGL's so copying from 32 bit + * SGL's to 64. + */ + if (sc->mfi_flags & MFI_FLAGS_SKINNY) { + sgl_ptr->Length = os_sgl->sg_skinny[i].len; + sgl_ptr->Address = os_sgl->sg_skinny[i].addr; + } else { + sgl_ptr->Length = os_sgl->sg32[i].len; + sgl_ptr->Address = os_sgl->sg32[i].addr; + } + sgl_ptr->Flags = 0; + sgl_ptr++; + cmd->io_request->ChainOffset = 0; + } + + sg_processed = i; + + if (sg_processed < sge_count) { + pMpi25IeeeSgeChain64_t sg_chain; + sg_to_process = sge_count - sg_processed; + cmd->io_request->ChainOffset = + sc->chain_offset_value_for_main_message; + sg_chain = sgl_ptr; + /* Prepare chain element */ + sg_chain->NextChainOffset = 0; + sg_chain->Flags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | + MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR); + sg_chain->Length = (sizeof(MPI2_SGE_IO_UNION) * + (sge_count - sg_processed)); + sg_chain->Address = cmd->sg_frame_phys_addr; + sgl_ptr = (pMpi25IeeeSgeChain64_t)cmd->sg_frame; + for (; i < sge_count; i++) { + if (sc->mfi_flags & MFI_FLAGS_SKINNY) { + sgl_ptr->Length = os_sgl->sg_skinny[i].len; + sgl_ptr->Address = os_sgl->sg_skinny[i].addr; + } else { + sgl_ptr->Length = os_sgl->sg32[i].len; + sgl_ptr->Address = os_sgl->sg32[i].addr; + } + sgl_ptr->Flags = 0; + sgl_ptr++; + } + } + return sge_count; +} + +union mfi_mpi2_request_descriptor * +mfi_build_and_issue_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd) +{ + struct mfi_cmd_tbolt *cmd; + union mfi_mpi2_request_descriptor *req_desc = NULL; + uint16_t index; + cmd = mfi_tbolt_get_cmd(sc); + if (!cmd) + return NULL; + mfi_cmd->cm_extra_frames = cmd->index; + cmd->sync_cmd_idx = mfi_cmd->cm_index; + + index = cmd->index; + req_desc = mfi_tbolt_get_request_descriptor(sc, index-1); + if (mfi_tbolt_build_io(sc, mfi_cmd, cmd)) + return NULL; + req_desc->header.SMID = index; + return req_desc; +} + +union mfi_mpi2_request_descriptor * +mfi_tbolt_build_mpt_cmd(struct mfi_softc *sc, struct mfi_command *cmd) +{ + union mfi_mpi2_request_descriptor *req_desc = NULL; + uint16_t index; + if (mfi_build_mpt_pass_thru(sc, cmd)) { + device_printf(sc->mfi_dev, "Couldn't build MFI pass thru " + "cmd\n"); + return NULL; + } + /* For fusion the frame_count variable is used for SMID */ + index = cmd->cm_extra_frames; + + req_desc = mfi_tbolt_get_request_descriptor(sc, index - 1); + if (!req_desc) + return NULL; + + bzero(req_desc, sizeof(req_desc)); + req_desc->header.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << + MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + req_desc->header.SMID = index; + return req_desc; +} + +int +mfi_tbolt_send_frame(struct mfi_softc *sc, struct mfi_command *cm) +{ + struct mfi_frame_header *hdr; + uint8_t *cdb; + union mfi_mpi2_request_descriptor *req_desc = NULL; + int tm = MFI_POLL_TIMEOUT_SECS * 1000; + + hdr = &cm->cm_frame->header; + cdb = cm->cm_frame->pass.cdb; + if (sc->adpreset) + return 1; + if ((cm->cm_flags & MFI_CMD_POLLED) == 0) { + cm->cm_timestamp = time_second; + mfi_enqueue_busy(cm); + } + else { + hdr->cmd_status = 0xff; + hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; + } + + if (hdr->cmd == MFI_CMD_PD_SCSI_IO) { + /* check for inquiry commands coming from CLI */ + if (cdb[0] != 0x28 || cdb[0] != 0x2A) { + if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == + NULL) { + device_printf(sc->mfi_dev, "Mapping from MFI " + "to MPT Failed \n"); + return 1; + } + } + else + device_printf(sc->mfi_dev, "DJA NA XXX SYSPDIO\n"); + } + else if (hdr->cmd == MFI_CMD_LD_SCSI_IO || + hdr->cmd == MFI_CMD_LD_READ || hdr->cmd == MFI_CMD_LD_WRITE) { + if ((req_desc = mfi_build_and_issue_cmd(sc, cm)) == NULL) { + device_printf(sc->mfi_dev, "LDIO Failed \n"); + return 1; + } + } else + if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == NULL) { + device_printf(sc->mfi_dev, "Mapping from MFI to MPT " + "Failed\n"); + return 1; + } + MFI_WRITE4(sc, MFI_ILQP, (req_desc->words & 0xFFFFFFFF)); + MFI_WRITE4(sc, MFI_IHQP, (req_desc->words >>0x20)); + + if ((cm->cm_flags & MFI_CMD_POLLED) == 0) + return 0; + + /* This is a polled command, so busy-wait for it to complete. */ + while (hdr->cmd_status == 0xff) { + DELAY(1000); + tm -= 1; + if (tm <= 0) + break; + } + + if (hdr->cmd_status == 0xff) { + device_printf(sc->mfi_dev, "Frame %p timed out " + "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode); + return (ETIMEDOUT); + } + return 0; +} + +static void mfi_issue_pending_cmds_again (struct mfi_softc *sc) +{ + struct mfi_command *cm, *tmp; + + KKASSERT(lockstatus(&sc->mfi_io_lock, curthread) != 0); + TAILQ_FOREACH_REVERSE_MUTABLE(cm, &sc->mfi_busy, BUSYQ, cm_link, tmp) { + + cm->retry_for_fw_reset++; + + /* + * If a command has continuously been tried multiple times + * and causing a FW reset condition, no further recoveries + * should be performed on the controller + */ + if (cm->retry_for_fw_reset == 3) { + device_printf(sc->mfi_dev, "megaraid_sas: command %d " + "was tried multiple times during adapter reset" + "Shutting down the HBA\n", cm->cm_index); + mfi_kill_hba(sc); + sc->hw_crit_error = 1; + return; + } + + if ((cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0) { + struct mfi_cmd_tbolt *cmd; + mfi_remove_busy(cm); + cmd = sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames - + 1 ]; + mfi_tbolt_return_cmd(sc, cmd); + if ((cm->cm_flags & MFI_ON_MFIQ_MASK) == 0) { + if (cm->cm_frame->dcmd.opcode != + MFI_DCMD_CTRL_EVENT_WAIT) { + device_printf(sc->mfi_dev, + "APJ ****requeue command %d \n", + cm->cm_index); + mfi_requeue_ready(cm); + } + } + else + mfi_release_command(cm); + } + } + mfi_startio(sc); +} + +static void mfi_kill_hba (struct mfi_softc *sc) +{ + if (sc->mfi_flags & MFI_FLAGS_TBOLT) + MFI_WRITE4 (sc, 0x00,MFI_STOP_ADP); + else + MFI_WRITE4 (sc, MFI_IDB,MFI_STOP_ADP); +} + +static void mfi_process_fw_state_chg_isr(void *arg) +{ + struct mfi_softc *sc= (struct mfi_softc *)arg; + struct mfi_cmd_tbolt *cmd; + int error, status; + + if (sc->adpreset == 1) { + device_printf(sc->mfi_dev, "First stage of FW reset " + "initiated...\n"); + + sc->mfi_adp_reset(sc); + sc->mfi_enable_intr(sc); + + device_printf(sc->mfi_dev, "First stage of reset complete, " + "second stage initiated...\n"); + + sc->adpreset = 2; + + /* waiting for about 20 second before start the second init */ + for (int wait = 0; wait < 20000; wait++) + DELAY(1000); + device_printf(sc->mfi_dev, "Second stage of FW reset " + "initiated...\n"); + while ((status = MFI_READ4(sc, MFI_RSR)) & 0x04); + + sc->mfi_disable_intr(sc); + + /* We expect the FW state to be READY */ + if (mfi_transition_firmware(sc)) { + device_printf(sc->mfi_dev, "controller is not in " + "ready state\n"); + mfi_kill_hba(sc); + sc->hw_crit_error= 1; + return ; + } + if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) + return; + + lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); + + sc->mfi_enable_intr(sc); + sc->adpreset = 0; + kfree(sc->mfi_aen_cm->cm_data, M_MFIBUF); + mfi_remove_busy(sc->mfi_aen_cm); + cmd = sc->mfi_cmd_pool_tbolt[sc->mfi_aen_cm->cm_extra_frames + - 1]; + mfi_tbolt_return_cmd(sc, cmd); + if (sc->mfi_aen_cm) { + mfi_release_command(sc->mfi_aen_cm); + sc->mfi_aen_cm = NULL; + } + if (sc->map_update_cmd) { + mfi_release_command(sc->map_update_cmd); + sc->map_update_cmd = NULL; + } + mfi_issue_pending_cmds_again(sc); + + /* + * Issue pending command can result in adapter being marked + * dead because of too many re-tries. Check for that + * condition before clearing the reset condition on the FW + */ + if (!sc->hw_crit_error) { + /* + * Initiate AEN (Asynchronous Event Notification) + */ + mfi_aen_setup(sc, sc->last_seq_num); + sc->issuepend_done = 1; + device_printf(sc->mfi_dev, "second stage of reset " + "complete, FW is ready now.\n"); + } else { + device_printf(sc->mfi_dev, "second stage of reset " + "never completed, hba was marked offline.\n"); + } + } else { + device_printf(sc->mfi_dev, "mfi_process_fw_state_chg_isr " + "called with unhandled value:%d\n", sc->adpreset); + } + lockmgr(&sc->mfi_io_lock, LK_RELEASE); +} diff --git a/sys/dev/raid/mfi/mfireg.h b/sys/dev/raid/mfi/mfireg.h index d64af712f6..c331497a40 100644 --- a/sys/dev/raid/mfi/mfireg.h +++ b/sys/dev/raid/mfi/mfireg.h @@ -48,38 +48,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - */ -/*- - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Copyright 1994-2009 The FreeBSD Project. - * All rights reserved. - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfireg.h,v 1.16 2011/07/14 20:20:33 jhb Exp $ + * FreeBSD projects/head_mfi/ r232888 */ #ifndef _MFIREG_H @@ -94,6 +65,8 @@ * seems to also call this interface 'MFI', so that will be used here. */ +#define MEGAMFI_FRAME_SIZE 64 + /* * Start with the register set. All registers are 32 bits wide. * The usual Intel IOP style setup. @@ -111,6 +84,14 @@ #define MFI_IQP 0x40 /* Inbound queue port */ #define MFI_OQP 0x44 /* Outbound queue port */ +/* + * ThunderBolt specific Register + */ + +#define MFI_RPI 0x6c /* reply_post_host_index */ +#define MFI_ILQP 0xc0 /* inbound_low_queue_port */ +#define MFI_IHQP 0xc4 /* inbound_high_queue_port */ + /* * 1078 specific related register */ @@ -122,18 +103,17 @@ #define MFI_1078_RM 0x80000000 /* reply 1078 message interrupt */ #define MFI_ODC 0x4 /* outbound doorbell change interrupt */ +/* OCR registers */ +#define MFI_WSR 0x004 /* write sequence register */ +#define MFI_HDR 0x008 /* host diagnostic register */ +#define MFI_RSR 0x3c3 /* Reset Status Register */ + /* * GEN2 specific changes */ #define MFI_GEN2_EIM 0x00000005 /* GEN2 enable interrupt mask */ #define MFI_GEN2_RM 0x00000001 /* reply GEN2 message interrupt */ -/* - * gen2 specific changes - */ -#define MFI_GEN2_EIM 0x00000005 /* gen2 enable interrupt mask */ -#define MFI_GEN2_RM 0x00000001 /* reply gen2 message interrupt */ - /* * skinny specific changes */ @@ -145,6 +125,10 @@ /* Bits for MFI_OSTS */ #define MFI_OSTS_INTR_VALID 0x00000002 +/* OCR specific flags */ +#define MFI_FIRMWARE_STATE_CHANGE 0x00000002 +#define MFI_STATE_CHANGE_INTERRUPT 0x00000004 /* MFI state change interrrupt */ + /* * Firmware state values. Found in OMSG0 during initialization. */ @@ -164,6 +148,14 @@ #define MFI_FWSTATE_MAXCMD_MASK 0x0000ffff #define MFI_FWSTATE_HOSTMEMREQD_MASK 0x08000000 #define MFI_FWSTATE_BOOT_MESSAGE_PENDING 0x90000000 +#define MFI_RESET_REQUIRED 0x00000001 + +/* ThunderBolt Support */ +#define MFI_FWSTATE_TB_MASK 0xf0000000 +#define MFI_FWSTATE_TB_RESET 0x00000000 +#define MFI_FWSTATE_TB_READY 0x10000000 +#define MFI_FWSTATE_TB_OPERATIONAL 0x20000000 +#define MFI_FWSTATE_TB_FAULT 0x40000000 /* * Control bits to drive the card to ready state. These go into the IDB @@ -175,6 +167,12 @@ #define MFI_FWINIT_CLEAR_HANDSHAKE 0x00000008 /* Respond to WAIT_HANDSHAKE */ #define MFI_FWINIT_HOTPLUG 0x00000010 +/* ADP reset flags */ +#define MFI_STOP_ADP 0x00000020 +#define MFI_ADP_RESET 0x00000040 +#define DIAG_WRITE_ENABLE 0x00000080 +#define DIAG_RESET_ADAPTER 0x00000004 + /* MFI Commands */ typedef enum { MFI_CMD_INIT = 0x00, @@ -220,6 +218,8 @@ typedef enum { MFI_DCMD_PD_GET_PROGRESS = 0x02060000, MFI_DCMD_PD_LOCATE_START = 0x02070100, MFI_DCMD_PD_LOCATE_STOP = 0x02070200, + MFI_DCMD_LD_MAP_GET_INFO = 0x0300e101, + MFI_DCMD_LD_SYNC = 0x0300e102, MFI_DCMD_LD_GET_LIST = 0x03010000, MFI_DCMD_LD_GET_INFO = 0x03020000, MFI_DCMD_LD_GET_PROP = 0x03030000, @@ -262,6 +262,35 @@ typedef enum { #define MFI_FRAME_DIR_BOTH 0x0018 #define MFI_FRAME_IEEE_SGL 0x0020 +/* ThunderBolt Specific */ + +/* + * Pre-TB command size and TB command size. + * We will be checking it at the load time for the time being + */ +#define MR_COMMAND_SIZE (MFI_FRAME_SIZE*20) /* 1280 bytes */ + +#define MEGASAS_THUNDERBOLT_MSG_ALLIGNMENT 256 +/* + * We are defining only 128 byte message to reduce memory move over head + * and also it will reduce the SRB extension size by 128byte compared with + * 256 message size + */ +#define MEGASAS_THUNDERBOLT_NEW_MSG_SIZE 256 +#define MEGASAS_THUNDERBOLT_MAX_COMMANDS 1024 +#define MEGASAS_THUNDERBOLT_MAX_REPLY_COUNT 1024 +#define MEGASAS_THUNDERBOLT_REPLY_SIZE 8 +#define MEGASAS_THUNDERBOLT_MAX_CHAIN_COUNT 1 +#define MEGASAS_MAX_SZ_CHAIN_FRAME 1024 + +#define MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0 +#define MPI2_FUNCTION_LD_IO_REQUEST 0xF1 + +#define MR_INTERNAL_MFI_FRAMES_SMID 1 +#define MR_CTRL_EVENT_WAIT_SMID 2 +#define MR_INTERNAL_DRIVER_RESET_SMID 3 + + /* MFI Status codes */ typedef enum { MFI_STAT_OK = 0x00, @@ -373,6 +402,10 @@ typedef enum { MR_EVT_ARGS_ECC } mfi_evt_args; +#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152 +#define MR_EVT_PD_REMOVED 0x0070 +#define MR_EVT_PD_INSERTED 0x005b + typedef enum { MR_LD_CACHE_WRITE_BACK = 0x01, MR_LD_CACHE_WRITE_ADAPTIVE = 0x02, @@ -406,7 +439,7 @@ typedef enum { MR_PD_QUERY_TYPE_POWER_STATE = 2, MR_PD_QUERY_TYPE_MEDIA_TYPE = 3, MR_PD_QUERY_TYPE_SPEED = 4, - MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, /*query for system drives */ + MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5 /*query for system drives */ } mfi_pd_query_type; /* @@ -448,9 +481,9 @@ struct mfi_sg_skinny { } __packed; union mfi_sgl { - struct mfi_sg32 sg32[1]; - struct mfi_sg64 sg64[1]; - struct mfi_sg_skinny sg_skinny[1]; + struct mfi_sg32 sg32[1]; + struct mfi_sg64 sg64[1]; + struct mfi_sg_skinny sg_skinny[1]; } __packed; /* Message frames. All messages have a common header */ @@ -466,7 +499,7 @@ struct mfi_frame_header { uint32_t context; /* * pad0 is MSI Specific. Not used by Driver. Zero the value before - * sending the command to f/w + * sending the command to f/w. */ uint32_t pad0; uint16_t flags; @@ -482,9 +515,29 @@ struct mfi_init_frame { uint32_t qinfo_new_addr_hi; uint32_t qinfo_old_addr_lo; uint32_t qinfo_old_addr_hi; - uint32_t reserved[6]; + // Start LSIP200113393 + uint32_t driver_ver_lo; /*28h */ + uint32_t driver_ver_hi; /*2Ch */ + + uint32_t reserved[4]; + // End LSIP200113393 } __packed; +/* + * Define MFI Address Context union. + */ +#ifdef MFI_ADDRESS_IS_uint64_t + typedef uint64_t MFI_ADDRESS; +#else + typedef union _MFI_ADDRESS { + struct { + uint32_t addressLow; + uint32_t addressHigh; + } u; + uint64_t address; + } MFI_ADDRESS, *PMFI_ADDRESS; +#endif + #define MFI_IO_FRAME_SIZE 40 struct mfi_io_frame { struct mfi_frame_header header; @@ -515,6 +568,7 @@ struct mfi_dcmd_frame { struct mfi_abort_frame { struct mfi_frame_header header; uint32_t abort_context; + /* pad is changed to reserved.*/ uint32_t reserved0; uint32_t abort_mfi_addr_lo; uint32_t abort_mfi_addr_hi; @@ -543,6 +597,7 @@ struct mfi_stp_frame { union mfi_frame { struct mfi_frame_header header; struct mfi_init_frame init; + /* ThunderBolt Initialization */ struct mfi_io_frame io; struct mfi_pass_frame pass; struct mfi_dcmd_frame dcmd; @@ -592,7 +647,61 @@ struct mfi_ctrl_props { uint16_t ecc_bucket_leak_rate; uint8_t restore_hotspare_on_insertion; uint8_t expose_encl_devices; - uint8_t reserved[38]; + uint8_t maintainPdFailHistory; + uint8_t disallowHostRequestReordering; + /* set TRUE to abort CC on detecting an inconsistency */ + uint8_t abortCCOnError; + /* load balance mode (MR_LOAD_BALANCE_MODE) */ + uint8_t loadBalanceMode; + /* + * 0 - use auto detect logic of backplanes like SGPIO, i2c SEP using + * h/w mechansim like GPIO pins + * 1 - disable auto detect SGPIO, + * 2 - disable i2c SEP auto detect + * 3 - disable both auto detect + */ + uint8_t disableAutoDetectBackplane; + /* + * % of source LD to be reserved for a VDs snapshot in snapshot + * repository, for metadata and user data: 1=5%, 2=10%, 3=15% and so on + */ + uint8_t snapVDSpace; + + /* + * Add properties that can be controlled by a bit in the following + * structure. + */ + struct { + /* set TRUE to disable copyBack (0=copback enabled) */ + uint32_t copyBackDisabled :1; + uint32_t SMARTerEnabled :1; + uint32_t prCorrectUnconfiguredAreas :1; + uint32_t useFdeOnly :1; + uint32_t disableNCQ :1; + uint32_t SSDSMARTerEnabled :1; + uint32_t SSDPatrolReadEnabled :1; + uint32_t enableSpinDownUnconfigured :1; + uint32_t autoEnhancedImport :1; + uint32_t enableSecretKeyControl :1; + uint32_t disableOnlineCtrlReset :1; + uint32_t allowBootWithPinnedCache :1; + uint32_t disableSpinDownHS :1; + uint32_t enableJBOD :1; + uint32_t reserved :18; + } OnOffProperties; + /* + * % of source LD to be reserved for auto snapshot in snapshot + * repository, for metadata and user data: 1=5%, 2=10%, 3=15% and so on. + */ + uint8_t autoSnapVDSpace; + /* + * Snapshot writeable VIEWs capacity as a % of source LD capacity: + * 0=READ only, 1=5%, 2=10%, 3=15% and so on. + */ + uint8_t viewSpace; + /* # of idle minutes before device is spun down (0=use FW defaults) */ + uint16_t spinDownTime; + uint8_t reserved[24]; } __packed; /* PCI information about the card. */ @@ -1152,7 +1261,7 @@ struct mfi_ld_info { uint8_t reserved2[16]; } __packed; -#define MAX_ARRAYS 16 +#define MAX_ARRAYS 128 struct mfi_spare { union mfi_pd_ref ref; uint8_t spare_type; @@ -1301,6 +1410,452 @@ struct mfi_pr_properties { uint32_t clear_freq; }; +/* ThunderBolt support */ + +/* + * Raid Context structure which describes MegaRAID specific IO Paramenters + * This resides at offset 0x60 where the SGL normally starts in MPT IO Frames + */ +typedef struct _MPI2_SCSI_IO_VENDOR_UNIQUE { + uint16_t resvd0; /* 0x00 - 0x01 */ + uint16_t timeoutValue; /* 0x02 - 0x03 */ + uint8_t regLockFlags; + uint8_t armId; + uint16_t TargetID; /* 0x06 - 0x07 */ + + uint64_t RegLockLBA; /* 0x08 - 0x0F */ + + uint32_t RegLockLength; /* 0x10 - 0x13 */ + + uint16_t SMID; /* 0x14 - 0x15 nextLMId */ + uint8_t exStatus; /* 0x16 */ + uint8_t Status; /* 0x17 status */ + + uint8_t RAIDFlags; /* 0x18 */ + uint8_t numSGE; /* 0x19 numSge */ + uint16_t configSeqNum; /* 0x1A - 0x1B */ + uint8_t spanArm; /* 0x1C */ + uint8_t resvd2[3]; /* 0x1D - 0x1F */ +} MPI2_SCSI_IO_VENDOR_UNIQUE, MPI25_SCSI_IO_VENDOR_UNIQUE; + +/*** DJA *****/ + +/***************************************************************************** +* +* Message Functions +* +*****************************************************************************/ + +#define NA_MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ +#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) /* SCSI Task Management */ +#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */ +#define MPI2_FUNCTION_IOC_FACTS (0x03) /* IOC Facts */ +#define MPI2_FUNCTION_CONFIG (0x04) /* Configuration */ +#define MPI2_FUNCTION_PORT_FACTS (0x05) /* Port Facts */ +#define MPI2_FUNCTION_PORT_ENABLE (0x06) /* Port Enable */ +#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) /* Event Notification */ +#define MPI2_FUNCTION_EVENT_ACK (0x08) /* Event Acknowledge */ +#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) /* FW Download */ +#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) /* Target Assist */ +#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) /* Target Status Send */ +#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) /* Target Mode Abort */ +#define MPI2_FUNCTION_FW_UPLOAD (0x12) /* FW Upload */ +#define MPI2_FUNCTION_RAID_ACTION (0x15) /* RAID Action */ +#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) /* SCSI IO RAID Passthrough */ +#define MPI2_FUNCTION_TOOLBOX (0x17) /* Toolbox */ +#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) /* SCSI Enclosure Processor */ +#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) /* SMP Passthrough */ +#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) /* SAS IO Unit Control */ +#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) /* SATA Passthrough */ +#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) /* Diagnostic Buffer Post */ +#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) /* Diagnostic Release */ +#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */ +#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */ +#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator */ +#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) /* Host Based Discovery Action */ +#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) /* Power Management Control */ +#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) /* beginning of product-specific range */ +#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) /* end of product-specific range */ + +/* Doorbell functions */ +#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) +#define MPI2_FUNCTION_HANDSHAKE (0x42) + +/***************************************************************************** +* +* MPI Version Definitions +* +*****************************************************************************/ + +#define MPI2_VERSION_MAJOR (0x02) +#define MPI2_VERSION_MINOR (0x00) +#define MPI2_VERSION_MAJOR_MASK (0xFF00) +#define MPI2_VERSION_MAJOR_SHIFT (8) +#define MPI2_VERSION_MINOR_MASK (0x00FF) +#define MPI2_VERSION_MINOR_SHIFT (0) +#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ + MPI2_VERSION_MINOR) + +#define MPI2_VERSION_02_00 (0x0200) + +/* versioning for this MPI header set */ +#define MPI2_HEADER_VERSION_UNIT (0x10) +#define MPI2_HEADER_VERSION_DEV (0x00) +#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) +#define MPI2_HEADER_VERSION_UNIT_SHIFT (8) +#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF) +#define MPI2_HEADER_VERSION_DEV_SHIFT (0) +#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | \ + MPI2_HEADER_VERSION_DEV) + + +/* IOCInit Request message */ +struct MPI2_IOC_INIT_REQUEST { + uint8_t WhoInit; /* 0x00 */ + uint8_t Reserved1; /* 0x01 */ + uint8_t ChainOffset; /* 0x02 */ + uint8_t Function; /* 0x03 */ + uint16_t Reserved2; /* 0x04 */ + uint8_t Reserved3; /* 0x06 */ + uint8_t MsgFlags; /* 0x07 */ + uint8_t VP_ID; /* 0x08 */ + uint8_t VF_ID; /* 0x09 */ + uint16_t Reserved4; /* 0x0A */ + uint16_t MsgVersion; /* 0x0C */ + uint16_t HeaderVersion; /* 0x0E */ + uint32_t Reserved5; /* 0x10 */ + uint16_t Reserved6; /* 0x14 */ + uint8_t Reserved7; /* 0x16 */ + uint8_t HostMSIxVectors; /* 0x17 */ + uint16_t Reserved8; /* 0x18 */ + uint16_t SystemRequestFrameSize; /* 0x1A */ + uint16_t ReplyDescriptorPostQueueDepth; /* 0x1C */ + uint16_t ReplyFreeQueueDepth; /* 0x1E */ + uint32_t SenseBufferAddressHigh; /* 0x20 */ + uint32_t SystemReplyAddressHigh; /* 0x24 */ + uint64_t SystemRequestFrameBaseAddress; /* 0x28 */ + uint64_t ReplyDescriptorPostQueueAddress;/* 0x30 */ + uint64_t ReplyFreeQueueAddress; /* 0x38 */ + uint64_t TimeStamp; /* 0x40 */ +}; + +/* WhoInit values */ +#define MPI2_WHOINIT_NOT_INITIALIZED (0x00) +#define MPI2_WHOINIT_SYSTEM_BIOS (0x01) +#define MPI2_WHOINIT_ROM_BIOS (0x02) +#define MPI2_WHOINIT_PCI_PEER (0x03) +#define MPI2_WHOINIT_HOST_DRIVER (0x04) +#define MPI2_WHOINIT_MANUFACTURER (0x05) + +struct MPI2_SGE_CHAIN_UNION { + uint16_t Length; + uint8_t NextChainOffset; + uint8_t Flags; + union { + uint32_t Address32; + uint64_t Address64; + } u; +}; + +struct MPI2_IEEE_SGE_SIMPLE32 { + uint32_t Address; + uint32_t FlagsLength; +}; + +struct MPI2_IEEE_SGE_SIMPLE64 { + uint64_t Address; + uint32_t Length; + uint16_t Reserved1; + uint8_t Reserved2; + uint8_t Flags; +}; + +typedef union _MPI2_IEEE_SGE_SIMPLE_UNION { + struct MPI2_IEEE_SGE_SIMPLE32 Simple32; + struct MPI2_IEEE_SGE_SIMPLE64 Simple64; +} MPI2_IEEE_SGE_SIMPLE_UNION; + +typedef struct _MPI2_SGE_SIMPLE_UNION { + uint32_t FlagsLength; + union { + uint32_t Address32; + uint64_t Address64; + } u; +} MPI2_SGE_SIMPLE_UNION; + +/**************************************************************************** +* IEEE SGE field definitions and masks +****************************************************************************/ + +/* Flags field bit definitions */ + +#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80) + +#define MPI2_IEEE32_SGE_FLAGS_SHIFT (24) + +#define MPI2_IEEE32_SGE_LENGTH_MASK (0x00FFFFFF) + +/* Element Type */ + +#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00) +#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80) + +/* Data Location Address Space */ + +#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) +#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) +#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) +#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) +#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) + +/* Address Size */ + +#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00) +#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) + +/*******************/ +/* SCSI IO Control bits */ +#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000) +#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26) + +#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000) +#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000) +#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) +#define MPI2_SCSIIO_CONTROL_READ (0x02000000) +#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000) + +#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800) +#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11) + +#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700) +#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000) +#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100) +#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200) +#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400) + +#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0) +#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000) +#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040) +#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080) + +/*******************/ + +typedef struct { + uint8_t CDB[20]; /* 0x00 */ + uint32_t PrimaryReferenceTag; /* 0x14 */ + uint16_t PrimaryApplicationTag; /* 0x18 */ + uint16_t PrimaryApplicationTagMask; /* 0x1A */ + uint32_t TransferLength; /* 0x1C */ +} MPI2_SCSI_IO_CDB_EEDP32; + + +typedef union _MPI2_IEEE_SGE_CHAIN_UNION { + struct MPI2_IEEE_SGE_SIMPLE32 Chain32; + struct MPI2_IEEE_SGE_SIMPLE64 Chain64; +} MPI2_IEEE_SGE_CHAIN_UNION; + +typedef union _MPI2_SIMPLE_SGE_UNION { + MPI2_SGE_SIMPLE_UNION MpiSimple; + MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; +} MPI2_SIMPLE_SGE_UNION; + +typedef union _MPI2_SGE_IO_UNION { + MPI2_SGE_SIMPLE_UNION MpiSimple; + struct MPI2_SGE_CHAIN_UNION MpiChain; + MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; + MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; +} MPI2_SGE_IO_UNION; + +typedef union { + uint8_t CDB32[32]; + MPI2_SCSI_IO_CDB_EEDP32 EEDP32; + MPI2_SGE_SIMPLE_UNION SGE; +} MPI2_SCSI_IO_CDB_UNION; + + +/* MPI 2.5 SGLs */ + +#define MPI25_IEEE_SGE_FLAGS_END_OF_LIST (0x40) + +typedef struct _MPI25_IEEE_SGE_CHAIN64 { + uint64_t Address; + uint32_t Length; + uint16_t Reserved1; + uint8_t NextChainOffset; + uint8_t Flags; +} MPI25_IEEE_SGE_CHAIN64, *pMpi25IeeeSgeChain64_t; + +/* use MPI2_IEEE_SGE_FLAGS_ defines for the Flags field */ + + +/********/ + +/* + * RAID SCSI IO Request Message + * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST + */ +struct mfi_mpi2_request_raid_scsi_io { + uint16_t DevHandle; /* 0x00 */ + uint8_t ChainOffset; /* 0x02 */ + uint8_t Function; /* 0x03 */ + uint16_t Reserved1; /* 0x04 */ + uint8_t Reserved2; /* 0x06 */ + uint8_t MsgFlags; /* 0x07 */ + uint8_t VP_ID; /* 0x08 */ + uint8_t VF_ID; /* 0x09 */ + uint16_t Reserved3; /* 0x0A */ + uint32_t SenseBufferLowAddress; /* 0x0C */ + uint16_t SGLFlags; /* 0x10 */ + uint8_t SenseBufferLength; /* 0x12 */ + uint8_t Reserved4; /* 0x13 */ + uint8_t SGLOffset0; /* 0x14 */ + uint8_t SGLOffset1; /* 0x15 */ + uint8_t SGLOffset2; /* 0x16 */ + uint8_t SGLOffset3; /* 0x17 */ + uint32_t SkipCount; /* 0x18 */ + uint32_t DataLength; /* 0x1C */ + uint32_t BidirectionalDataLength; /* 0x20 */ + uint16_t IoFlags; /* 0x24 */ + uint16_t EEDPFlags; /* 0x26 */ + uint32_t EEDPBlockSize; /* 0x28 */ + uint32_t SecondaryReferenceTag; /* 0x2C */ + uint16_t SecondaryApplicationTag; /* 0x30 */ + uint16_t ApplicationTagTranslationMask; /* 0x32 */ + uint8_t LUN[8]; /* 0x34 */ + uint32_t Control; /* 0x3C */ + MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ + MPI2_SCSI_IO_VENDOR_UNIQUE RaidContext; /* 0x60 */ + MPI2_SGE_IO_UNION SGL; /* 0x80 */ +} __packed; + +/* + * MPT RAID MFA IO Descriptor. + */ +typedef struct _MFI_RAID_MFA_IO_DESCRIPTOR { + uint32_t RequestFlags : 8; + uint32_t MessageAddress1 : 24; /* bits 31:8*/ + uint32_t MessageAddress2; /* bits 61:32 */ +} MFI_RAID_MFA_IO_REQUEST_DESCRIPTOR,*PMFI_RAID_MFA_IO_REQUEST_DESCRIPTOR; + +struct mfi_mpi2_request_header { + uint8_t RequestFlags; /* 0x00 */ + uint8_t MSIxIndex; /* 0x01 */ + uint16_t SMID; /* 0x02 */ + uint16_t LMID; /* 0x04 */ +}; + +/* defines for the RequestFlags field */ +#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E) +#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) +#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02) +#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) +#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08) +#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A) + +#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01) + +struct mfi_mpi2_request_high_priority { + struct mfi_mpi2_request_header header; + uint16_t reserved; +}; + +struct mfi_mpi2_request_scsi_io { + struct mfi_mpi2_request_header header; + uint16_t scsi_io_dev_handle; +}; + +struct mfi_mpi2_request_scsi_target { + struct mfi_mpi2_request_header header; + uint16_t scsi_target_io_index; +}; + +/* Request Descriptors */ +union mfi_mpi2_request_descriptor { + struct mfi_mpi2_request_header header; + struct mfi_mpi2_request_high_priority high_priority; + struct mfi_mpi2_request_scsi_io scsi_io; + struct mfi_mpi2_request_scsi_target scsi_target; + uint64_t words; +}; + + +struct mfi_mpi2_reply_header { + uint8_t ReplyFlags; /* 0x00 */ + uint8_t MSIxIndex; /* 0x01 */ + uint16_t SMID; /* 0x02 */ +}; + +/* defines for the ReplyFlags field */ +#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) +#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) +#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03) +#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05) +#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) + +/* values for marking a reply descriptor as unused */ +#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF) +#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK (0xFFFFFFFF) + +struct mfi_mpi2_reply_default { + struct mfi_mpi2_reply_header header; + uint32_t DescriptorTypeDependent2; +}; + +struct mfi_mpi2_reply_address { + struct mfi_mpi2_reply_header header; + uint32_t ReplyFrameAddress; +}; + +struct mfi_mpi2_reply_scsi_io { + struct mfi_mpi2_reply_header header; + uint16_t TaskTag; /* 0x04 */ + uint16_t Reserved1; /* 0x06 */ +}; + +struct mfi_mpi2_reply_target_assist { + struct mfi_mpi2_reply_header header; + uint8_t SequenceNumber; /* 0x04 */ + uint8_t Reserved1; /* 0x04 */ + uint16_t IoIndex; /* 0x06 */ +}; + +struct mfi_mpi2_reply_target_cmd_buffer { + struct mfi_mpi2_reply_header header; + uint8_t SequenceNumber; /* 0x04 */ + uint8_t Flags; /* 0x04 */ + uint16_t InitiatorDevHandle; /* 0x06 */ + uint16_t IoIndex; /* 0x06 */ +}; + +struct mfi_mpi2_reply_raid_accel { + struct mfi_mpi2_reply_header header; + uint8_t SequenceNumber; /* 0x04 */ + uint32_t Reserved; /* 0x04 */ +}; + +/* union of Reply Descriptors */ +union mfi_mpi2_reply_descriptor { + struct mfi_mpi2_reply_header header; + struct mfi_mpi2_reply_scsi_io scsi_io; + struct mfi_mpi2_reply_target_assist target_assist; + struct mfi_mpi2_reply_target_cmd_buffer target_cmd; + struct mfi_mpi2_reply_raid_accel raid_accel; + struct mfi_mpi2_reply_default reply_default; + uint64_t words; +}; + +struct IO_REQUEST_INFO { + uint64_t ldStartBlock; + uint32_t numBlocks; + uint16_t ldTgtId; + uint8_t isRead; + uint16_t devHandle; + uint64_t pdBlock; + uint8_t fpOkForIo; +}; + #define MFI_SCSI_MAX_TARGETS 128 #define MFI_SCSI_MAX_LUNS 8 #define MFI_SCSI_INITIATOR_ID 255 diff --git a/sys/dev/raid/mfi/mfivar.h b/sys/dev/raid/mfi/mfivar.h index 56518a8c9b..0de856bfd2 100644 --- a/sys/dev/raid/mfi/mfivar.h +++ b/sys/dev/raid/mfi/mfivar.h @@ -48,38 +48,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - */ -/*- - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Copyright 1994-2009 The FreeBSD Project. - * All rights reserved. - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies,either expressed or implied, of the FreeBSD Project. * * $FreeBSD: src/sys/dev/mfi/mfivar.h,v 1.14 2011/09/29 08:37:53 mav Exp $ + * FreeBSD projects/head_mfi/ r232949 */ #ifndef _MFIVAR_H @@ -90,6 +61,7 @@ #include #include #include +#include /* * SCSI structures and definitions are used from here, but no linking @@ -103,6 +75,9 @@ struct mfi_hwcomms { uint32_t hw_reply_q[1]; }; +#define MEGASAS_MAX_NAME 32 +#define MEGASAS_VERSION "4.23" + struct mfi_softc; struct disk; struct ccb_hdr; @@ -112,17 +87,9 @@ struct mfi_command { time_t cm_timestamp; struct mfi_softc *cm_sc; union mfi_frame *cm_frame; -#if defined(__x86_64__) - uint64_t cm_frame_busaddr; -#else - uint32_t cm_frame_busaddr; -#endif + bus_addr_t cm_frame_busaddr; struct mfi_sense *cm_sense; -#if defined(__x86_64__) - uint64_t cm_sense_busaddr; -#else - uint32_t cm_sense_busaddr; -#endif + bus_addr_t cm_sense_busaddr; bus_dmamap_t cm_dmamap; union mfi_sgl *cm_sg; void *cm_data; @@ -141,6 +108,7 @@ struct mfi_command { #define MFI_ON_MFIQ_BUSY (1<<7) #define MFI_ON_MFIQ_MASK ((1<<5)|(1<<6)|(1<<7)) int cm_aen_abort; + uint8_t retry_for_fw_reset; void (* cm_complete)(struct mfi_command *cm); void *cm_private; int cm_index; @@ -182,11 +150,31 @@ struct mfi_system_pd { int pd_flags; }; +struct mfi_evt_queue_elm { + TAILQ_ENTRY(mfi_evt_queue_elm) link; + struct mfi_evt_detail detail; +}; + struct mfi_aen { TAILQ_ENTRY(mfi_aen) aen_link; struct proc *p; }; +struct mfi_skinny_dma_info { + bus_dma_tag_t dmat[514]; + bus_dmamap_t dmamap[514]; + uint32_t mem[514]; + int noofmaps; +}; + +struct mfi_cmd_tbolt; +typedef struct { + volatile unsigned int val; +} atomic_t; + +#define atomic_read(v) ((v)->val) +#define atomic_set(v,i) ((v)->val - (i)) + struct mfi_softc { device_t mfi_dev; int mfi_flags; @@ -198,11 +186,21 @@ struct mfi_softc { #define MFI_FLAGS_1078 (1<<5) #define MFI_FLAGS_GEN2 (1<<6) #define MFI_FLAGS_SKINNY (1<<7) +#define MFI_FLAGS_TBOLT (1<<8) + // Start: LSIP200113393 + bus_dma_tag_t verbuf_h_dmat; + bus_dmamap_t verbuf_h_dmamap; + uint32_t verbuf_h_busaddr; + uint32_t *verbuf; + void *kbuff_arr[MAX_IOCTL_SGE]; + bus_dma_tag_t mfi_kbuff_arr_dmat[2]; + bus_dmamap_t mfi_kbuff_arr_dmamap[2]; + bus_addr_t mfi_kbuff_arr_busaddr[2]; struct mfi_hwcomms *mfi_comms; TAILQ_HEAD(,mfi_command) mfi_free; TAILQ_HEAD(,mfi_command) mfi_ready; - TAILQ_HEAD(,mfi_command) mfi_busy; + TAILQ_HEAD(BUSYQ,mfi_command) mfi_busy; struct bio_queue_head mfi_bioq; struct mfi_qstat mfi_qstat[MFIQ_COUNT]; @@ -216,19 +214,28 @@ struct mfi_softc { bus_dma_tag_t mfi_comms_dmat; bus_dmamap_t mfi_comms_dmamap; - uint32_t mfi_comms_busaddr; + bus_addr_t mfi_comms_busaddr; bus_dma_tag_t mfi_frames_dmat; bus_dmamap_t mfi_frames_dmamap; - uint32_t mfi_frames_busaddr; + bus_addr_t mfi_frames_busaddr; union mfi_frame *mfi_frames; + bus_dma_tag_t mfi_tb_init_dmat; + bus_dmamap_t mfi_tb_init_dmamap; + bus_addr_t mfi_tb_init_busaddr; + bus_addr_t mfi_tb_ioc_init_busaddr; + union mfi_frame *mfi_tb_init; + + TAILQ_HEAD(,mfi_evt_queue_elm) mfi_evt_queue; + struct task mfi_evt_task; TAILQ_HEAD(,mfi_aen) mfi_aen_pids; struct mfi_command *mfi_aen_cm; struct mfi_command *mfi_skinny_cm; uint32_t mfi_aen_triggered; uint32_t mfi_poll_waiting; struct kqinfo mfi_kq; + uint32_t mfi_boot_seq_num; int mfi_delete_busy_volumes; int mfi_keep_deleted_volumes; int mfi_detaching; @@ -245,6 +252,14 @@ struct mfi_softc { struct intr_config_hook mfi_ich; eventhandler_tag eh; + /* OCR flags */ + atomic_t fw_reset_no_pci_access; + uint8_t adpreset; + uint8_t issuepend_done; + uint8_t disableOnlineCtrlReset; + uint32_t mfiStatus; + uint32_t last_seq_num; + uint32_t volatile hw_crit_error; /* * Allocation for the command array. Used as an indexable array to @@ -295,9 +310,98 @@ struct mfi_softc { /* Controller type specific interfaces */ void (*mfi_enable_intr)(struct mfi_softc *sc); + void (*mfi_disable_intr)(struct mfi_softc *sc); int32_t (*mfi_read_fw_status)(struct mfi_softc *sc); int (*mfi_check_clear_intr)(struct mfi_softc *sc); - void (*mfi_issue_cmd)(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt); + void (*mfi_issue_cmd)(struct mfi_softc *sc, bus_addr_t bus_add, + uint32_t frame_cnt); + int (*mfi_adp_reset)(struct mfi_softc *sc); + int (*mfi_adp_check_reset)(struct mfi_softc *sc); + + /* ThunderBolt */ + uint32_t mfi_tbolt; + uint32_t MFA_enabled; + uint64_t map_id; + struct mfi_command *map_update_cmd; + /* Single Reply structure size */ + uint16_t reply_size; + /* Singler message size. */ + uint16_t raid_io_msg_size; + TAILQ_HEAD(TB, mfi_cmd_tbolt) mfi_cmd_tbolt_tqh; + /* ThunderBolt base contiguous memory mapping. */ + bus_dma_tag_t mfi_tb_dmat; + bus_dmamap_t mfi_tb_dmamap; + bus_addr_t mfi_tb_busaddr; + /* ThunderBolt Contiguous DMA memory Mapping */ + uint8_t * request_message_pool; + uint8_t * request_message_pool_align; + uint8_t * request_desc_pool; + //uint32_t request_desc_busaddr; + bus_addr_t request_msg_busaddr; + bus_addr_t reply_frame_busaddr; + bus_addr_t sg_frame_busaddr; + /* ThunderBolt IOC Init Descriptor */ + bus_dma_tag_t mfi_tb_ioc_init_dmat; + bus_dmamap_t mfi_tb_ioc_init_dmamap; + uint8_t * mfi_tb_ioc_init_desc; + struct mfi_cmd_tbolt **mfi_cmd_pool_tbolt; + /* Virtual address of reply Frame Pool */ + struct mfi_mpi2_reply_header* reply_frame_pool; + struct mfi_mpi2_reply_header* reply_frame_pool_align; + + /* Last reply frame address */ + uint8_t * reply_pool_limit; + uint16_t last_reply_idx; + uint8_t max_SGEs_in_chain_message; + uint8_t max_SGEs_in_main_message; + uint8_t chain_offset_value_for_main_message; + uint8_t chain_offset_value_for_mpt_ptmsg; +}; + +union desc_value { + uint64_t word; + struct { + uint32_t low; + uint32_t high; + }u; +}; + +// TODO find the right definition +#define XXX_MFI_CMD_OP_INIT2 0x9 +/* + * Request descriptor types + */ +#define MFI_REQ_DESCRIPT_FLAGS_LD_IO 0x7 +#define MFI_REQ_DESCRIPT_FLAGS_MFA 0x1 +#define MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT 0x1 +#define MFI_FUSION_FP_DEFAULT_TIMEOUT 0x14 +#define MFI_LOAD_BALANCE_FLAG 0x1 +#define MFI_DCMD_MBOX_PEND_FLAG 0x1 + +//#define MR_PROT_INFO_TYPE_CONTROLLER 0x08 +#define MEGASAS_SCSI_VARIABLE_LENGTH_CMD 0x7f +#define MEGASAS_SCSI_SERVICE_ACTION_READ32 0x9 +#define MEGASAS_SCSI_SERVICE_ACTION_WRITE32 0xB +#define MEGASAS_SCSI_ADDL_CDB_LEN 0x18 +#define MEGASAS_RD_WR_PROTECT_CHECK_ALL 0x20 +#define MEGASAS_RD_WR_PROTECT_CHECK_NONE 0x60 +#define MEGASAS_EEDPBLOCKSIZE 512 +struct mfi_cmd_tbolt { + union mfi_mpi2_request_descriptor *request_desc; + struct mfi_mpi2_request_raid_scsi_io *io_request; + bus_addr_t io_request_phys_addr; + bus_addr_t sg_frame_phys_addr; + bus_addr_t sense_phys_addr; + MPI2_SGE_IO_UNION *sg_frame; + uint8_t *sense; + TAILQ_ENTRY(mfi_cmd_tbolt) next; + /* + * Context for a MFI frame. + * Used to get the mfi cmd from list when a MFI cmd is completed + */ + uint32_t sync_cmd_idx; + uint16_t index; + uint8_t status; }; extern int mfi_attach(struct mfi_softc *); @@ -310,7 +414,28 @@ extern void mfi_disk_enable(struct mfi_disk *); extern int mfi_dump_blocks(struct mfi_softc *, int id, uint64_t, void *, int); extern int mfi_syspd_disable(struct mfi_system_pd *); extern void mfi_syspd_enable(struct mfi_system_pd *); -extern int mfi_dump_syspd_blocks(struct mfi_softc *, int id, uint64_t, void *, int); +extern int mfi_dump_syspd_blocks(struct mfi_softc *, int id, uint64_t, void *, + int); +extern int mfi_transition_firmware(struct mfi_softc *sc); +extern int mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start); +extern void mfi_complete(struct mfi_softc *sc, struct mfi_command *cm); +extern int mfi_mapcmd(struct mfi_softc *sc,struct mfi_command *cm); +extern int mfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm); +extern void mfi_tbolt_enable_intr_ppc(struct mfi_softc *); +extern void mfi_tbolt_disable_intr_ppc(struct mfi_softc *); +extern int32_t mfi_tbolt_read_fw_status_ppc(struct mfi_softc *); +extern int32_t mfi_tbolt_check_clear_intr_ppc(struct mfi_softc *); +extern void mfi_tbolt_issue_cmd_ppc(struct mfi_softc *, bus_addr_t, uint32_t); +extern void mfi_tbolt_init_globals(struct mfi_softc*); +extern uint32_t mfi_tbolt_get_memory_requirement(struct mfi_softc *); +extern int mfi_tbolt_init_desc_pool(struct mfi_softc *, uint8_t *, uint32_t); +extern int mfi_tbolt_init_MFI_queue(struct mfi_softc *); +extern void mfi_intr_tbolt(void *arg); +extern int mfi_tbolt_alloc_cmd(struct mfi_softc *sc); +extern int mfi_tbolt_send_frame(struct mfi_softc *sc, struct mfi_command *cm); +extern int mfi_tbolt_adp_reset(struct mfi_softc *sc); +extern int mfi_tbolt_reset(struct mfi_softc *sc); +extern int mfi_tbolt_sync_map_info(struct mfi_softc *sc); #define MFIQ_ADD(sc, qname) \ do { \ @@ -451,9 +576,10 @@ mfi_print_sense(struct mfi_softc *sc, void *sense) MALLOC_DECLARE(M_MFIBUF); +#define MFI_RESET_WAIT_TIME 180 #define MFI_CMD_TIMEOUT 30 -#define MFI_MAXPHYS (128 * 1024) #define SKINNY_MEMORY 0x02000000 +#define MFI_MAXPHYS (128 * 1024) #ifdef MFI_DEBUG extern void mfi_print_cmd(struct mfi_command *cm); -- 2.41.0