mfi.c revision 242681
1157114Sscottl/*- 2157114Sscottl * Copyright (c) 2006 IronPort Systems 3157114Sscottl * All rights reserved. 4157114Sscottl * 5157114Sscottl * Redistribution and use in source and binary forms, with or without 6157114Sscottl * modification, are permitted provided that the following conditions 7157114Sscottl * are met: 8157114Sscottl * 1. Redistributions of source code must retain the above copyright 9157114Sscottl * notice, this list of conditions and the following disclaimer. 10157114Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11157114Sscottl * notice, this list of conditions and the following disclaimer in the 12157114Sscottl * documentation and/or other materials provided with the distribution. 13157114Sscottl * 14157114Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15157114Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16157114Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17157114Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18157114Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19157114Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20157114Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21157114Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22157114Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23157114Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24157114Sscottl * SUCH DAMAGE. 25157114Sscottl */ 26171980Sscottl/*- 27171980Sscottl * Copyright (c) 2007 LSI Corp. 28171980Sscottl * Copyright (c) 2007 Rajesh Prabhakaran. 29171980Sscottl * All rights reserved. 30171980Sscottl * 31171980Sscottl * Redistribution and use in source and binary forms, with or without 32171980Sscottl * modification, are permitted provided that the following conditions 33171980Sscottl * are met: 34171980Sscottl * 1. Redistributions of source code must retain the above copyright 35171980Sscottl * notice, this list of conditions and the following disclaimer. 36171980Sscottl * 2. Redistributions in binary form must reproduce the above copyright 37171980Sscottl * notice, this list of conditions and the following disclaimer in the 38171980Sscottl * documentation and/or other materials provided with the distribution. 39171980Sscottl * 40171980Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 41171980Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42171980Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 43171980Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 44171980Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 45171980Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 46171980Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47171980Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 48171980Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 49171980Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 50171980Sscottl * SUCH DAMAGE. 51171980Sscottl */ 52157114Sscottl 53157114Sscottl#include <sys/cdefs.h> 54157114Sscottl__FBSDID("$FreeBSD: head/sys/dev/mfi/mfi.c 242681 2012-11-06 23:25:06Z ambrisko $"); 55157114Sscottl 56233711Sambrisko#include "opt_compat.h" 57157114Sscottl#include "opt_mfi.h" 58157114Sscottl 59157114Sscottl#include <sys/param.h> 60157114Sscottl#include <sys/systm.h> 61162118Sambrisko#include <sys/sysctl.h> 62157114Sscottl#include <sys/malloc.h> 63157114Sscottl#include <sys/kernel.h> 64158737Sambrisko#include <sys/poll.h> 65158737Sambrisko#include <sys/selinfo.h> 66157114Sscottl#include <sys/bus.h> 67157114Sscottl#include <sys/conf.h> 68157114Sscottl#include <sys/eventhandler.h> 69157114Sscottl#include <sys/rman.h> 70157114Sscottl#include <sys/bus_dma.h> 71157114Sscottl#include <sys/bio.h> 72157114Sscottl#include <sys/ioccom.h> 73158737Sambrisko#include <sys/uio.h> 74158737Sambrisko#include <sys/proc.h> 75163398Sscottl#include <sys/signalvar.h> 76238077Sjhb#include <sys/sysent.h> 77233711Sambrisko#include <sys/taskqueue.h> 78157114Sscottl 79157114Sscottl#include <machine/bus.h> 80157114Sscottl#include <machine/resource.h> 81157114Sscottl 82157114Sscottl#include <dev/mfi/mfireg.h> 83157114Sscottl#include <dev/mfi/mfi_ioctl.h> 84157114Sscottl#include <dev/mfi/mfivar.h> 85233711Sambrisko#include <sys/interrupt.h> 86233711Sambrisko#include <sys/priority.h> 87157114Sscottl 88157114Sscottlstatic int mfi_alloc_commands(struct mfi_softc *); 89157114Sscottlstatic int mfi_comms_init(struct mfi_softc *); 90157114Sscottlstatic int mfi_get_controller_info(struct mfi_softc *); 91158737Sambriskostatic int mfi_get_log_state(struct mfi_softc *, 92159806Sps struct mfi_evt_log_state **); 93180037Sjhbstatic int mfi_parse_entries(struct mfi_softc *, int, int); 94157114Sscottlstatic void mfi_data_cb(void *, bus_dma_segment_t *, int, int); 95157114Sscottlstatic void mfi_startup(void *arg); 96157114Sscottlstatic void mfi_intr(void *arg); 97159811Spsstatic void mfi_ldprobe(struct mfi_softc *sc); 98233711Sambriskostatic void mfi_syspdprobe(struct mfi_softc *sc); 99233711Sambriskostatic void mfi_handle_evt(void *context, int pending); 100158737Sambriskostatic int mfi_aen_register(struct mfi_softc *sc, int seq, int locale); 101158737Sambriskostatic void mfi_aen_complete(struct mfi_command *); 102159811Spsstatic int mfi_add_ld(struct mfi_softc *sc, int); 103159811Spsstatic void mfi_add_ld_complete(struct mfi_command *); 104233711Sambriskostatic int mfi_add_sys_pd(struct mfi_softc *sc, int); 105233711Sambriskostatic void mfi_add_sys_pd_complete(struct mfi_command *); 106157114Sscottlstatic struct mfi_command * mfi_bio_command(struct mfi_softc *); 107157114Sscottlstatic void mfi_bio_complete(struct mfi_command *); 108233711Sambriskostatic struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*); 109233711Sambriskostatic struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*); 110157114Sscottlstatic int mfi_send_frame(struct mfi_softc *, struct mfi_command *); 111242681Sambriskostatic int mfi_abort(struct mfi_softc *, struct mfi_command **); 112192450Simpstatic int mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, struct thread *); 113162619Sscottlstatic void mfi_timeout(void *); 114178968Sscottlstatic int mfi_user_command(struct mfi_softc *, 115178968Sscottl struct mfi_ioc_passthru *); 116233711Sambriskostatic void mfi_enable_intr_xscale(struct mfi_softc *sc); 117233711Sambriskostatic void mfi_enable_intr_ppc(struct mfi_softc *sc); 118233711Sambriskostatic int32_t mfi_read_fw_status_xscale(struct mfi_softc *sc); 119233711Sambriskostatic int32_t mfi_read_fw_status_ppc(struct mfi_softc *sc); 120233711Sambriskostatic int mfi_check_clear_intr_xscale(struct mfi_softc *sc); 121233711Sambriskostatic int mfi_check_clear_intr_ppc(struct mfi_softc *sc); 122233711Sambriskostatic void mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, 123233711Sambrisko uint32_t frame_cnt); 124233711Sambriskostatic void mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, 125233711Sambrisko uint32_t frame_cnt); 126233711Sambriskostatic int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode); 127233711Sambriskostatic void mfi_config_unlock(struct mfi_softc *sc, int locked); 128233711Sambriskostatic int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm); 129233711Sambriskostatic void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm); 130233711Sambriskostatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm); 131157114Sscottl 132227562SjhbSYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters"); 133162118Sambriskostatic int mfi_event_locale = MFI_EVT_LOCALE_ALL; 134162473SambriskoTUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale); 135162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RW, &mfi_event_locale, 136162118Sambrisko 0, "event message locale"); 137162473Sambrisko 138165852Sscottlstatic int mfi_event_class = MFI_EVT_CLASS_INFO; 139162473SambriskoTUNABLE_INT("hw.mfi.event_class", &mfi_event_class); 140162118SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RW, &mfi_event_class, 141162118Sambrisko 0, "event message class"); 142162118Sambrisko 143178968Sscottlstatic int mfi_max_cmds = 128; 144178968SscottlTUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds); 145178968SscottlSYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RD, &mfi_max_cmds, 146178968Sscottl 0, "Max commands"); 147178968Sscottl 148233711Sambriskostatic int mfi_detect_jbod_change = 1; 149233711SambriskoTUNABLE_INT("hw.mfi.detect_jbod_change", &mfi_detect_jbod_change); 150233711SambriskoSYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RW, 151233711Sambrisko &mfi_detect_jbod_change, 0, "Detect a change to a JBOD"); 152233711Sambrisko 153157114Sscottl/* Management interface */ 154157114Sscottlstatic d_open_t mfi_open; 155157114Sscottlstatic d_close_t mfi_close; 156157114Sscottlstatic d_ioctl_t mfi_ioctl; 157158737Sambriskostatic d_poll_t mfi_poll; 158157114Sscottl 159157114Sscottlstatic struct cdevsw mfi_cdevsw = { 160157114Sscottl .d_version = D_VERSION, 161157114Sscottl .d_flags = 0, 162157114Sscottl .d_open = mfi_open, 163157114Sscottl .d_close = mfi_close, 164157114Sscottl .d_ioctl = mfi_ioctl, 165158737Sambrisko .d_poll = mfi_poll, 166157114Sscottl .d_name = "mfi", 167157114Sscottl}; 168157114Sscottl 169157114SscottlMALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver"); 170157114Sscottl 171158737Sambrisko#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH 172233711Sambriskostruct mfi_skinny_dma_info mfi_skinny; 173157114Sscottl 174171980Sscottlstatic void 175171980Sscottlmfi_enable_intr_xscale(struct mfi_softc *sc) 176171980Sscottl{ 177171980Sscottl MFI_WRITE4(sc, MFI_OMSK, 0x01); 178171980Sscottl} 179171980Sscottl 180171980Sscottlstatic void 181171980Sscottlmfi_enable_intr_ppc(struct mfi_softc *sc) 182171980Sscottl{ 183184897Sambrisko if (sc->mfi_flags & MFI_FLAGS_1078) { 184233711Sambrisko MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF); 185184897Sambrisko MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM); 186233711Sambrisko } 187233711Sambrisko else if (sc->mfi_flags & MFI_FLAGS_GEN2) { 188233711Sambrisko MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF); 189184897Sambrisko MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM); 190184897Sambrisko } 191233711Sambrisko else if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 192233711Sambrisko MFI_WRITE4(sc, MFI_OMSK, ~0x00000001); 193233711Sambrisko } 194171980Sscottl} 195171980Sscottl 196171980Sscottlstatic int32_t 197171980Sscottlmfi_read_fw_status_xscale(struct mfi_softc *sc) 198171980Sscottl{ 199171980Sscottl return MFI_READ4(sc, MFI_OMSG0); 200171980Sscottl} 201184897Sambrisko 202171980Sscottlstatic int32_t 203171980Sscottlmfi_read_fw_status_ppc(struct mfi_softc *sc) 204171980Sscottl{ 205171980Sscottl return MFI_READ4(sc, MFI_OSP0); 206171980Sscottl} 207171980Sscottl 208184897Sambriskostatic int 209171980Sscottlmfi_check_clear_intr_xscale(struct mfi_softc *sc) 210171980Sscottl{ 211171980Sscottl int32_t status; 212171980Sscottl 213171980Sscottl status = MFI_READ4(sc, MFI_OSTS); 214171980Sscottl if ((status & MFI_OSTS_INTR_VALID) == 0) 215171980Sscottl return 1; 216171980Sscottl 217171980Sscottl MFI_WRITE4(sc, MFI_OSTS, status); 218171980Sscottl return 0; 219182085Simp} 220171980Sscottl 221184897Sambriskostatic int 222171980Sscottlmfi_check_clear_intr_ppc(struct mfi_softc *sc) 223171980Sscottl{ 224171980Sscottl int32_t status; 225171980Sscottl 226171980Sscottl status = MFI_READ4(sc, MFI_OSTS); 227184897Sambrisko if (sc->mfi_flags & MFI_FLAGS_1078) { 228184897Sambrisko if (!(status & MFI_1078_RM)) { 229184897Sambrisko return 1; 230184897Sambrisko } 231233711Sambrisko } 232233711Sambrisko else if (sc->mfi_flags & MFI_FLAGS_GEN2) { 233184897Sambrisko if (!(status & MFI_GEN2_RM)) { 234184897Sambrisko return 1; 235184897Sambrisko } 236184897Sambrisko } 237233711Sambrisko else if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 238233711Sambrisko if (!(status & MFI_SKINNY_RM)) { 239233711Sambrisko return 1; 240233711Sambrisko } 241233711Sambrisko } 242233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) 243233711Sambrisko MFI_WRITE4(sc, MFI_OSTS, status); 244233711Sambrisko else 245233711Sambrisko MFI_WRITE4(sc, MFI_ODCR0, status); 246171980Sscottl return 0; 247182085Simp} 248171980Sscottl 249184897Sambriskostatic void 250233711Sambriskomfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt) 251171980Sscottl{ 252171980Sscottl MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt); 253171980Sscottl} 254184897Sambrisko 255184897Sambriskostatic void 256233711Sambriskomfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt) 257171980Sscottl{ 258233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 259233711Sambrisko MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt <<1)|1 ); 260233711Sambrisko MFI_WRITE4(sc, MFI_IQPH, 0x00000000); 261233711Sambrisko } else { 262233711Sambrisko MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt <<1)|1 ); 263233711Sambrisko } 264171980Sscottl} 265171980Sscottl 266233711Sambriskoint 267157114Sscottlmfi_transition_firmware(struct mfi_softc *sc) 268157114Sscottl{ 269194851Sscottl uint32_t fw_state, cur_state; 270157114Sscottl int max_wait, i; 271233711Sambrisko uint32_t cur_abs_reg_val = 0; 272233711Sambrisko uint32_t prev_abs_reg_val = 0; 273157114Sscottl 274233711Sambrisko cur_abs_reg_val = sc->mfi_read_fw_status(sc); 275233711Sambrisko fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK; 276157114Sscottl while (fw_state != MFI_FWSTATE_READY) { 277157114Sscottl if (bootverbose) 278157114Sscottl device_printf(sc->mfi_dev, "Waiting for firmware to " 279171980Sscottl "become ready\n"); 280157114Sscottl cur_state = fw_state; 281157114Sscottl switch (fw_state) { 282157114Sscottl case MFI_FWSTATE_FAULT: 283157114Sscottl device_printf(sc->mfi_dev, "Firmware fault\n"); 284157114Sscottl return (ENXIO); 285157114Sscottl case MFI_FWSTATE_WAIT_HANDSHAKE: 286233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 287233711Sambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE); 288233711Sambrisko else 289233711Sambrisko MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE); 290233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 291157114Sscottl break; 292157114Sscottl case MFI_FWSTATE_OPERATIONAL: 293233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 294233711Sambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, 7); 295233711Sambrisko else 296233711Sambrisko MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY); 297233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 298157114Sscottl break; 299157114Sscottl case MFI_FWSTATE_UNDEFINED: 300157114Sscottl case MFI_FWSTATE_BB_INIT: 301233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 302157114Sscottl break; 303233711Sambrisko case MFI_FWSTATE_FW_INIT_2: 304233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 305233711Sambrisko break; 306157114Sscottl case MFI_FWSTATE_FW_INIT: 307157114Sscottl case MFI_FWSTATE_FLUSH_CACHE: 308233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 309157114Sscottl break; 310233711Sambrisko case MFI_FWSTATE_DEVICE_SCAN: 311233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */ 312233711Sambrisko prev_abs_reg_val = cur_abs_reg_val; 313233711Sambrisko break; 314224041Sjhb case MFI_FWSTATE_BOOT_MESSAGE_PENDING: 315233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 316233711Sambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG); 317233711Sambrisko else 318233711Sambrisko MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG); 319233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 320224041Sjhb break; 321157114Sscottl default: 322233711Sambrisko device_printf(sc->mfi_dev, "Unknown firmware state %#x\n", 323157114Sscottl fw_state); 324157114Sscottl return (ENXIO); 325157114Sscottl } 326157114Sscottl for (i = 0; i < (max_wait * 10); i++) { 327233711Sambrisko cur_abs_reg_val = sc->mfi_read_fw_status(sc); 328233711Sambrisko fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK; 329157114Sscottl if (fw_state == cur_state) 330157114Sscottl DELAY(100000); 331157114Sscottl else 332157114Sscottl break; 333157114Sscottl } 334233711Sambrisko if (fw_state == MFI_FWSTATE_DEVICE_SCAN) { 335233711Sambrisko /* Check the device scanning progress */ 336233711Sambrisko if (prev_abs_reg_val != cur_abs_reg_val) { 337233711Sambrisko continue; 338233711Sambrisko } 339233711Sambrisko } 340157114Sscottl if (fw_state == cur_state) { 341224041Sjhb device_printf(sc->mfi_dev, "Firmware stuck in state " 342157114Sscottl "%#x\n", fw_state); 343157114Sscottl return (ENXIO); 344157114Sscottl } 345157114Sscottl } 346157114Sscottl return (0); 347157114Sscottl} 348157114Sscottl 349157114Sscottlstatic void 350233711Sambriskomfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 351157114Sscottl{ 352233711Sambrisko bus_addr_t *addr; 353157114Sscottl 354157114Sscottl addr = arg; 355157114Sscottl *addr = segs[0].ds_addr; 356157114Sscottl} 357157114Sscottl 358233711Sambrisko 359157114Sscottlint 360157114Sscottlmfi_attach(struct mfi_softc *sc) 361157114Sscottl{ 362157114Sscottl uint32_t status; 363157114Sscottl int error, commsz, framessz, sensesz; 364162458Sscottl int frames, unit, max_fw_sge; 365233711Sambrisko uint32_t tb_mem_size = 0; 366157114Sscottl 367233711Sambrisko if (sc == NULL) 368233711Sambrisko return EINVAL; 369186132Sambrisko 370233711Sambrisko device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n", 371233711Sambrisko MEGASAS_VERSION); 372233711Sambrisko 373157114Sscottl mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF); 374171821Sjhb sx_init(&sc->mfi_config_lock, "MFI config"); 375157114Sscottl TAILQ_INIT(&sc->mfi_ld_tqh); 376233711Sambrisko TAILQ_INIT(&sc->mfi_syspd_tqh); 377242681Sambrisko TAILQ_INIT(&sc->mfi_ld_pend_tqh); 378242681Sambrisko TAILQ_INIT(&sc->mfi_syspd_pend_tqh); 379233711Sambrisko TAILQ_INIT(&sc->mfi_evt_queue); 380233711Sambrisko TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc); 381235014Sambrisko TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc); 382158737Sambrisko TAILQ_INIT(&sc->mfi_aen_pids); 383169611Sscottl TAILQ_INIT(&sc->mfi_cam_ccbq); 384157114Sscottl 385157114Sscottl mfi_initq_free(sc); 386157114Sscottl mfi_initq_ready(sc); 387157114Sscottl mfi_initq_busy(sc); 388157114Sscottl mfi_initq_bio(sc); 389157114Sscottl 390233711Sambrisko sc->adpreset = 0; 391233711Sambrisko sc->last_seq_num = 0; 392233711Sambrisko sc->disableOnlineCtrlReset = 1; 393233711Sambrisko sc->issuepend_done = 1; 394233711Sambrisko sc->hw_crit_error = 0; 395233711Sambrisko 396171980Sscottl if (sc->mfi_flags & MFI_FLAGS_1064R) { 397171980Sscottl sc->mfi_enable_intr = mfi_enable_intr_xscale; 398171980Sscottl sc->mfi_read_fw_status = mfi_read_fw_status_xscale; 399171980Sscottl sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale; 400171980Sscottl sc->mfi_issue_cmd = mfi_issue_cmd_xscale; 401233711Sambrisko } else if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 402233711Sambrisko sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc; 403233711Sambrisko sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc; 404233711Sambrisko sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc; 405233711Sambrisko sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc; 406233711Sambrisko sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc; 407233711Sambrisko sc->mfi_adp_reset = mfi_tbolt_adp_reset; 408233711Sambrisko sc->mfi_tbolt = 1; 409233711Sambrisko TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh); 410233711Sambrisko } else { 411171980Sscottl sc->mfi_enable_intr = mfi_enable_intr_ppc; 412233711Sambrisko sc->mfi_read_fw_status = mfi_read_fw_status_ppc; 413171980Sscottl sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc; 414171980Sscottl sc->mfi_issue_cmd = mfi_issue_cmd_ppc; 415171980Sscottl } 416171980Sscottl 417171980Sscottl 418157114Sscottl /* Before we get too far, see if the firmware is working */ 419157114Sscottl if ((error = mfi_transition_firmware(sc)) != 0) { 420157114Sscottl device_printf(sc->mfi_dev, "Firmware not in READY state, " 421157114Sscottl "error %d\n", error); 422157114Sscottl return (ENXIO); 423157114Sscottl } 424157114Sscottl 425233711Sambrisko /* Start: LSIP200113393 */ 426233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 427233711Sambrisko 1, 0, /* algnmnt, boundary */ 428233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 429233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 430233711Sambrisko NULL, NULL, /* filter, filterarg */ 431233711Sambrisko MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsize */ 432233711Sambrisko 1, /* msegments */ 433233711Sambrisko MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsegsize */ 434233711Sambrisko 0, /* flags */ 435233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 436233711Sambrisko &sc->verbuf_h_dmat)) { 437233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n"); 438233711Sambrisko return (ENOMEM); 439233711Sambrisko } 440233711Sambrisko if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf, 441233711Sambrisko BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) { 442233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n"); 443233711Sambrisko return (ENOMEM); 444233711Sambrisko } 445233711Sambrisko bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t)); 446233711Sambrisko bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap, 447233711Sambrisko sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t), 448233711Sambrisko mfi_addr_cb, &sc->verbuf_h_busaddr, 0); 449233711Sambrisko /* End: LSIP200113393 */ 450233711Sambrisko 451157114Sscottl /* 452157114Sscottl * Get information needed for sizing the contiguous memory for the 453157114Sscottl * frame pool. Size down the sgl parameter since we know that 454157114Sscottl * we will never need more than what's required for MAXPHYS. 455157114Sscottl * It would be nice if these constants were available at runtime 456157114Sscottl * instead of compile time. 457157114Sscottl */ 458171980Sscottl status = sc->mfi_read_fw_status(sc); 459157114Sscottl sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK; 460162458Sscottl max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16; 461195534Sscottl sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1)); 462157114Sscottl 463233711Sambrisko /* ThunderBolt Support get the contiguous memory */ 464233711Sambrisko 465233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 466233711Sambrisko mfi_tbolt_init_globals(sc); 467233711Sambrisko device_printf(sc->mfi_dev, "MaxCmd = %x MaxSgl = %x state = %x \n", 468233711Sambrisko sc->mfi_max_fw_cmds, sc->mfi_max_sge, status); 469233711Sambrisko tb_mem_size = mfi_tbolt_get_memory_requirement(sc); 470233711Sambrisko 471233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 472233711Sambrisko 1, 0, /* algnmnt, boundary */ 473233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 474233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 475233711Sambrisko NULL, NULL, /* filter, filterarg */ 476233711Sambrisko tb_mem_size, /* maxsize */ 477233711Sambrisko 1, /* msegments */ 478233711Sambrisko tb_mem_size, /* maxsegsize */ 479233711Sambrisko 0, /* flags */ 480233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 481233711Sambrisko &sc->mfi_tb_dmat)) { 482233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n"); 483233711Sambrisko return (ENOMEM); 484233711Sambrisko } 485233711Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool, 486233711Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) { 487233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 488233711Sambrisko return (ENOMEM); 489233711Sambrisko } 490233711Sambrisko bzero(sc->request_message_pool, tb_mem_size); 491233711Sambrisko bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap, 492233711Sambrisko sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0); 493233711Sambrisko 494233711Sambrisko /* For ThunderBolt memory init */ 495233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 496233711Sambrisko 0x100, 0, /* alignmnt, boundary */ 497233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 498233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 499233711Sambrisko NULL, NULL, /* filter, filterarg */ 500233711Sambrisko MFI_FRAME_SIZE, /* maxsize */ 501233711Sambrisko 1, /* msegments */ 502233711Sambrisko MFI_FRAME_SIZE, /* maxsegsize */ 503233711Sambrisko 0, /* flags */ 504233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 505233711Sambrisko &sc->mfi_tb_init_dmat)) { 506233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n"); 507233711Sambrisko return (ENOMEM); 508233711Sambrisko } 509233711Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init, 510233711Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) { 511233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate init memory\n"); 512233711Sambrisko return (ENOMEM); 513233711Sambrisko } 514233711Sambrisko bzero(sc->mfi_tb_init, MFI_FRAME_SIZE); 515233711Sambrisko bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap, 516233711Sambrisko sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb, 517233711Sambrisko &sc->mfi_tb_init_busaddr, 0); 518233711Sambrisko if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool, 519233711Sambrisko tb_mem_size)) { 520233711Sambrisko device_printf(sc->mfi_dev, 521233711Sambrisko "Thunderbolt pool preparation error\n"); 522233711Sambrisko return 0; 523233711Sambrisko } 524233711Sambrisko 525233711Sambrisko /* 526233711Sambrisko Allocate DMA memory mapping for MPI2 IOC Init descriptor, 527233711Sambrisko we are taking it diffrent from what we have allocated for Request 528233711Sambrisko and reply descriptors to avoid confusion later 529233711Sambrisko */ 530233711Sambrisko tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST); 531233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 532233711Sambrisko 1, 0, /* algnmnt, boundary */ 533233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 534233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 535233711Sambrisko NULL, NULL, /* filter, filterarg */ 536233711Sambrisko tb_mem_size, /* maxsize */ 537233711Sambrisko 1, /* msegments */ 538233711Sambrisko tb_mem_size, /* maxsegsize */ 539233711Sambrisko 0, /* flags */ 540233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 541233711Sambrisko &sc->mfi_tb_ioc_init_dmat)) { 542233711Sambrisko device_printf(sc->mfi_dev, 543233711Sambrisko "Cannot allocate comms DMA tag\n"); 544233711Sambrisko return (ENOMEM); 545233711Sambrisko } 546233711Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat, 547233711Sambrisko (void **)&sc->mfi_tb_ioc_init_desc, 548233711Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) { 549233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 550233711Sambrisko return (ENOMEM); 551233711Sambrisko } 552233711Sambrisko bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size); 553233711Sambrisko bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap, 554233711Sambrisko sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb, 555233711Sambrisko &sc->mfi_tb_ioc_init_busaddr, 0); 556233711Sambrisko } 557157114Sscottl /* 558157114Sscottl * Create the dma tag for data buffers. Used both for block I/O 559157114Sscottl * and for various internal data queries. 560157114Sscottl */ 561157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 562157114Sscottl 1, 0, /* algnmnt, boundary */ 563157114Sscottl BUS_SPACE_MAXADDR, /* lowaddr */ 564157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 565157114Sscottl NULL, NULL, /* filter, filterarg */ 566157114Sscottl BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 567162458Sscottl sc->mfi_max_sge, /* nsegments */ 568157114Sscottl BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 569157114Sscottl BUS_DMA_ALLOCNOW, /* flags */ 570157114Sscottl busdma_lock_mutex, /* lockfunc */ 571157114Sscottl &sc->mfi_io_lock, /* lockfuncarg */ 572157114Sscottl &sc->mfi_buffer_dmat)) { 573157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n"); 574157114Sscottl return (ENOMEM); 575157114Sscottl } 576157114Sscottl 577157114Sscottl /* 578157114Sscottl * Allocate DMA memory for the comms queues. Keep it under 4GB for 579157114Sscottl * efficiency. The mfi_hwcomms struct includes space for 1 reply queue 580157114Sscottl * entry, so the calculated size here will be will be 1 more than 581157114Sscottl * mfi_max_fw_cmds. This is apparently a requirement of the hardware. 582157114Sscottl */ 583157114Sscottl commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) + 584157114Sscottl sizeof(struct mfi_hwcomms); 585157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 586157114Sscottl 1, 0, /* algnmnt, boundary */ 587157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 588157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 589157114Sscottl NULL, NULL, /* filter, filterarg */ 590157114Sscottl commsz, /* maxsize */ 591157114Sscottl 1, /* msegments */ 592157114Sscottl commsz, /* maxsegsize */ 593157114Sscottl 0, /* flags */ 594157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 595157114Sscottl &sc->mfi_comms_dmat)) { 596157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n"); 597157114Sscottl return (ENOMEM); 598157114Sscottl } 599157114Sscottl if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms, 600157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) { 601157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 602157114Sscottl return (ENOMEM); 603157114Sscottl } 604157114Sscottl bzero(sc->mfi_comms, commsz); 605157114Sscottl bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap, 606233711Sambrisko sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0); 607157114Sscottl /* 608157114Sscottl * Allocate DMA memory for the command frames. Keep them in the 609162458Sscottl * lower 4GB for efficiency. Calculate the size of the commands at 610162458Sscottl * the same time; each command is one 64 byte frame plus a set of 611162458Sscottl * additional frames for holding sg lists or other data. 612157114Sscottl * The assumption here is that the SG list will start at the second 613162458Sscottl * frame and not use the unused bytes in the first frame. While this 614162458Sscottl * isn't technically correct, it simplifies the calculation and allows 615162458Sscottl * for command frames that might be larger than an mfi_io_frame. 616157114Sscottl */ 617157114Sscottl if (sizeof(bus_addr_t) == 8) { 618162458Sscottl sc->mfi_sge_size = sizeof(struct mfi_sg64); 619157114Sscottl sc->mfi_flags |= MFI_FLAGS_SG64; 620157114Sscottl } else { 621162458Sscottl sc->mfi_sge_size = sizeof(struct mfi_sg32); 622157114Sscottl } 623233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) 624233711Sambrisko sc->mfi_sge_size = sizeof(struct mfi_sg_skinny); 625162458Sscottl frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2; 626162458Sscottl sc->mfi_cmd_size = frames * MFI_FRAME_SIZE; 627162458Sscottl framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds; 628157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 629157114Sscottl 64, 0, /* algnmnt, boundary */ 630157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 631157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 632157114Sscottl NULL, NULL, /* filter, filterarg */ 633157114Sscottl framessz, /* maxsize */ 634157114Sscottl 1, /* nsegments */ 635157114Sscottl framessz, /* maxsegsize */ 636157114Sscottl 0, /* flags */ 637157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 638157114Sscottl &sc->mfi_frames_dmat)) { 639157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n"); 640157114Sscottl return (ENOMEM); 641157114Sscottl } 642157114Sscottl if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames, 643157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) { 644157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate frames memory\n"); 645157114Sscottl return (ENOMEM); 646157114Sscottl } 647157114Sscottl bzero(sc->mfi_frames, framessz); 648157114Sscottl bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap, 649233711Sambrisko sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0); 650157114Sscottl /* 651157114Sscottl * Allocate DMA memory for the frame sense data. Keep them in the 652157114Sscottl * lower 4GB for efficiency 653157114Sscottl */ 654157114Sscottl sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN; 655157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 656157114Sscottl 4, 0, /* algnmnt, boundary */ 657157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 658157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 659157114Sscottl NULL, NULL, /* filter, filterarg */ 660157114Sscottl sensesz, /* maxsize */ 661157114Sscottl 1, /* nsegments */ 662157114Sscottl sensesz, /* maxsegsize */ 663157114Sscottl 0, /* flags */ 664157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 665157114Sscottl &sc->mfi_sense_dmat)) { 666157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n"); 667157114Sscottl return (ENOMEM); 668157114Sscottl } 669157114Sscottl if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense, 670157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) { 671157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate sense memory\n"); 672157114Sscottl return (ENOMEM); 673157114Sscottl } 674157114Sscottl bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap, 675233711Sambrisko sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0); 676157114Sscottl if ((error = mfi_alloc_commands(sc)) != 0) 677157114Sscottl return (error); 678157114Sscottl 679233711Sambrisko /* Before moving the FW to operational state, check whether 680233711Sambrisko * hostmemory is required by the FW or not 681233711Sambrisko */ 682157114Sscottl 683233711Sambrisko /* ThunderBolt MFI_IOC2 INIT */ 684233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 685233711Sambrisko sc->mfi_disable_intr(sc); 686233711Sambrisko if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) { 687233711Sambrisko device_printf(sc->mfi_dev, 688233711Sambrisko "TB Init has failed with error %d\n",error); 689233711Sambrisko return error; 690233711Sambrisko } 691157114Sscottl 692233711Sambrisko if ((error = mfi_tbolt_alloc_cmd(sc)) != 0) 693233711Sambrisko return error; 694233711Sambrisko if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, 695233711Sambrisko INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc, 696233711Sambrisko &sc->mfi_intr)) { 697233711Sambrisko device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); 698233711Sambrisko return (EINVAL); 699233711Sambrisko } 700242681Sambrisko sc->mfi_intr_ptr = mfi_intr_tbolt; 701233711Sambrisko sc->mfi_enable_intr(sc); 702233711Sambrisko } else { 703233711Sambrisko if ((error = mfi_comms_init(sc)) != 0) 704233711Sambrisko return (error); 705157114Sscottl 706233711Sambrisko if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, 707233711Sambrisko INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) { 708233711Sambrisko device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); 709233711Sambrisko return (EINVAL); 710233711Sambrisko } 711242681Sambrisko sc->mfi_intr_ptr = mfi_intr; 712233711Sambrisko sc->mfi_enable_intr(sc); 713157114Sscottl } 714233711Sambrisko if ((error = mfi_get_controller_info(sc)) != 0) 715233711Sambrisko return (error); 716233711Sambrisko sc->disableOnlineCtrlReset = 0; 717157114Sscottl 718157114Sscottl /* Register a config hook to probe the bus for arrays */ 719157114Sscottl sc->mfi_ich.ich_func = mfi_startup; 720157114Sscottl sc->mfi_ich.ich_arg = sc; 721157114Sscottl if (config_intrhook_establish(&sc->mfi_ich) != 0) { 722157114Sscottl device_printf(sc->mfi_dev, "Cannot establish configuration " 723157114Sscottl "hook\n"); 724157114Sscottl return (EINVAL); 725157114Sscottl } 726233711Sambrisko if ((error = mfi_aen_setup(sc, 0), 0) != 0) { 727233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 728233711Sambrisko return (error); 729233711Sambrisko } 730157114Sscottl 731157114Sscottl /* 732157114Sscottl * Register a shutdown handler. 733157114Sscottl */ 734157114Sscottl if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown, 735157114Sscottl sc, SHUTDOWN_PRI_DEFAULT)) == NULL) { 736157114Sscottl device_printf(sc->mfi_dev, "Warning: shutdown event " 737157114Sscottl "registration failed\n"); 738157114Sscottl } 739157114Sscottl 740157114Sscottl /* 741157114Sscottl * Create the control device for doing management 742157114Sscottl */ 743157114Sscottl unit = device_get_unit(sc->mfi_dev); 744157114Sscottl sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR, 745157114Sscottl 0640, "mfi%d", unit); 746158737Sambrisko if (unit == 0) 747158737Sambrisko make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node"); 748157114Sscottl if (sc->mfi_cdev != NULL) 749157114Sscottl sc->mfi_cdev->si_drv1 = sc; 750171821Sjhb SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev), 751171821Sjhb SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), 752171821Sjhb OID_AUTO, "delete_busy_volumes", CTLFLAG_RW, 753171821Sjhb &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes"); 754171821Sjhb SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev), 755171821Sjhb SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), 756171821Sjhb OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW, 757171821Sjhb &sc->mfi_keep_deleted_volumes, 0, 758171821Sjhb "Don't detach the mfid device for a busy volume that is deleted"); 759157114Sscottl 760169611Sscottl device_add_child(sc->mfi_dev, "mfip", -1); 761169611Sscottl bus_generic_attach(sc->mfi_dev); 762169611Sscottl 763162619Sscottl /* Start the timeout watchdog */ 764178250Skris callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE); 765162619Sscottl callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, 766162619Sscottl mfi_timeout, sc); 767162619Sscottl 768235014Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 769235014Sambrisko mfi_tbolt_sync_map_info(sc); 770235014Sambrisko } 771235014Sambrisko 772157114Sscottl return (0); 773157114Sscottl} 774157114Sscottl 775157114Sscottlstatic int 776157114Sscottlmfi_alloc_commands(struct mfi_softc *sc) 777157114Sscottl{ 778157114Sscottl struct mfi_command *cm; 779157114Sscottl int i, ncmds; 780157114Sscottl 781157114Sscottl /* 782157114Sscottl * XXX Should we allocate all the commands up front, or allocate on 783157114Sscottl * demand later like 'aac' does? 784157114Sscottl */ 785178968Sscottl ncmds = MIN(mfi_max_cmds, sc->mfi_max_fw_cmds); 786178968Sscottl if (bootverbose) 787178968Sscottl device_printf(sc->mfi_dev, "Max fw cmds= %d, sizing driver " 788178968Sscottl "pool to %d\n", sc->mfi_max_fw_cmds, ncmds); 789178968Sscottl 790157114Sscottl sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF, 791157114Sscottl M_WAITOK | M_ZERO); 792157114Sscottl 793157114Sscottl for (i = 0; i < ncmds; i++) { 794157114Sscottl cm = &sc->mfi_commands[i]; 795158737Sambrisko cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames + 796162458Sscottl sc->mfi_cmd_size * i); 797157114Sscottl cm->cm_frame_busaddr = sc->mfi_frames_busaddr + 798162458Sscottl sc->mfi_cmd_size * i; 799157114Sscottl cm->cm_frame->header.context = i; 800157114Sscottl cm->cm_sense = &sc->mfi_sense[i]; 801157114Sscottl cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i; 802157114Sscottl cm->cm_sc = sc; 803162619Sscottl cm->cm_index = i; 804157114Sscottl if (bus_dmamap_create(sc->mfi_buffer_dmat, 0, 805233711Sambrisko &cm->cm_dmamap) == 0) { 806233711Sambrisko mtx_lock(&sc->mfi_io_lock); 807157114Sscottl mfi_release_command(cm); 808233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 809233711Sambrisko } 810157114Sscottl else 811157114Sscottl break; 812157114Sscottl sc->mfi_total_cmds++; 813157114Sscottl } 814157114Sscottl 815157114Sscottl return (0); 816157114Sscottl} 817157114Sscottl 818169611Sscottlvoid 819157114Sscottlmfi_release_command(struct mfi_command *cm) 820157114Sscottl{ 821163398Sscottl struct mfi_frame_header *hdr; 822157114Sscottl uint32_t *hdr_data; 823157114Sscottl 824233711Sambrisko mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED); 825233711Sambrisko 826157114Sscottl /* 827157114Sscottl * Zero out the important fields of the frame, but make sure the 828165727Sscottl * context field is preserved. For efficiency, handle the fields 829165727Sscottl * as 32 bit words. Clear out the first S/G entry too for safety. 830157114Sscottl */ 831163398Sscottl hdr = &cm->cm_frame->header; 832175897Sambrisko if (cm->cm_data != NULL && hdr->sg_count) { 833163398Sscottl cm->cm_sg->sg32[0].len = 0; 834163398Sscottl cm->cm_sg->sg32[0].addr = 0; 835163398Sscottl } 836165727Sscottl 837165727Sscottl hdr_data = (uint32_t *)cm->cm_frame; 838165727Sscottl hdr_data[0] = 0; /* cmd, sense_len, cmd_status, scsi_status */ 839165727Sscottl hdr_data[1] = 0; /* target_id, lun_id, cdb_len, sg_count */ 840165727Sscottl hdr_data[4] = 0; /* flags, timeout */ 841165727Sscottl hdr_data[5] = 0; /* data_len */ 842165727Sscottl 843157114Sscottl cm->cm_extra_frames = 0; 844157114Sscottl cm->cm_flags = 0; 845157114Sscottl cm->cm_complete = NULL; 846157114Sscottl cm->cm_private = NULL; 847169611Sscottl cm->cm_data = NULL; 848157114Sscottl cm->cm_sg = 0; 849157114Sscottl cm->cm_total_frame_size = 0; 850233711Sambrisko cm->retry_for_fw_reset = 0; 851163398Sscottl 852157114Sscottl mfi_enqueue_free(cm); 853157114Sscottl} 854157114Sscottl 855235014Sambriskoint 856233711Sambriskomfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, 857233711Sambrisko uint32_t opcode, void **bufp, size_t bufsize) 858159806Sps{ 859159806Sps struct mfi_command *cm; 860159806Sps struct mfi_dcmd_frame *dcmd; 861159806Sps void *buf = NULL; 862233711Sambrisko uint32_t context = 0; 863233711Sambrisko 864159806Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 865233711Sambrisko 866159806Sps cm = mfi_dequeue_free(sc); 867159806Sps if (cm == NULL) 868159806Sps return (EBUSY); 869159806Sps 870233711Sambrisko /* Zero out the MFI frame */ 871233711Sambrisko context = cm->cm_frame->header.context; 872233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 873233711Sambrisko cm->cm_frame->header.context = context; 874233711Sambrisko 875159806Sps if ((bufsize > 0) && (bufp != NULL)) { 876159806Sps if (*bufp == NULL) { 877159806Sps buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO); 878159806Sps if (buf == NULL) { 879159806Sps mfi_release_command(cm); 880159806Sps return (ENOMEM); 881159806Sps } 882159806Sps *bufp = buf; 883159806Sps } else { 884159806Sps buf = *bufp; 885159806Sps } 886159806Sps } 887159806Sps 888159806Sps dcmd = &cm->cm_frame->dcmd; 889159806Sps bzero(dcmd->mbox, MFI_MBOX_SIZE); 890159806Sps dcmd->header.cmd = MFI_CMD_DCMD; 891159806Sps dcmd->header.timeout = 0; 892159806Sps dcmd->header.flags = 0; 893159806Sps dcmd->header.data_len = bufsize; 894233711Sambrisko dcmd->header.scsi_status = 0; 895159806Sps dcmd->opcode = opcode; 896159806Sps cm->cm_sg = &dcmd->sgl; 897159806Sps cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 898159806Sps cm->cm_flags = 0; 899159806Sps cm->cm_data = buf; 900159806Sps cm->cm_private = buf; 901159806Sps cm->cm_len = bufsize; 902159806Sps 903159806Sps *cmp = cm; 904159806Sps if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL)) 905159806Sps *bufp = buf; 906159806Sps return (0); 907159806Sps} 908159806Sps 909159806Spsstatic int 910157114Sscottlmfi_comms_init(struct mfi_softc *sc) 911157114Sscottl{ 912157114Sscottl struct mfi_command *cm; 913157114Sscottl struct mfi_init_frame *init; 914157114Sscottl struct mfi_init_qinfo *qinfo; 915157114Sscottl int error; 916233711Sambrisko uint32_t context = 0; 917157114Sscottl 918163398Sscottl mtx_lock(&sc->mfi_io_lock); 919157114Sscottl if ((cm = mfi_dequeue_free(sc)) == NULL) 920157114Sscottl return (EBUSY); 921157114Sscottl 922233711Sambrisko /* Zero out the MFI frame */ 923233711Sambrisko context = cm->cm_frame->header.context; 924233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 925233711Sambrisko cm->cm_frame->header.context = context; 926233711Sambrisko 927157114Sscottl /* 928157114Sscottl * Abuse the SG list area of the frame to hold the init_qinfo 929157114Sscottl * object; 930157114Sscottl */ 931157114Sscottl init = &cm->cm_frame->init; 932157114Sscottl qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE); 933157114Sscottl 934157114Sscottl bzero(qinfo, sizeof(struct mfi_init_qinfo)); 935157114Sscottl qinfo->rq_entries = sc->mfi_max_fw_cmds + 1; 936157114Sscottl qinfo->rq_addr_lo = sc->mfi_comms_busaddr + 937157114Sscottl offsetof(struct mfi_hwcomms, hw_reply_q); 938157114Sscottl qinfo->pi_addr_lo = sc->mfi_comms_busaddr + 939157114Sscottl offsetof(struct mfi_hwcomms, hw_pi); 940157114Sscottl qinfo->ci_addr_lo = sc->mfi_comms_busaddr + 941157114Sscottl offsetof(struct mfi_hwcomms, hw_ci); 942157114Sscottl 943157114Sscottl init->header.cmd = MFI_CMD_INIT; 944157114Sscottl init->header.data_len = sizeof(struct mfi_init_qinfo); 945157114Sscottl init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE; 946164375Sscottl cm->cm_data = NULL; 947164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 948157114Sscottl 949164375Sscottl if ((error = mfi_mapcmd(sc, cm)) != 0) { 950157114Sscottl device_printf(sc->mfi_dev, "failed to send init command\n"); 951163398Sscottl mtx_unlock(&sc->mfi_io_lock); 952157114Sscottl return (error); 953157114Sscottl } 954157114Sscottl mfi_release_command(cm); 955163398Sscottl mtx_unlock(&sc->mfi_io_lock); 956157114Sscottl 957157114Sscottl return (0); 958157114Sscottl} 959157114Sscottl 960157114Sscottlstatic int 961157114Sscottlmfi_get_controller_info(struct mfi_softc *sc) 962157114Sscottl{ 963159806Sps struct mfi_command *cm = NULL; 964159806Sps struct mfi_ctrl_info *ci = NULL; 965157114Sscottl uint32_t max_sectors_1, max_sectors_2; 966157114Sscottl int error; 967157114Sscottl 968159806Sps mtx_lock(&sc->mfi_io_lock); 969159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO, 970159806Sps (void **)&ci, sizeof(*ci)); 971159806Sps if (error) 972159806Sps goto out; 973157114Sscottl cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 974157114Sscottl 975157114Sscottl if ((error = mfi_mapcmd(sc, cm)) != 0) { 976157114Sscottl device_printf(sc->mfi_dev, "Failed to get controller info\n"); 977162458Sscottl sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE / 978157114Sscottl MFI_SECTOR_LEN; 979159806Sps error = 0; 980159806Sps goto out; 981157114Sscottl } 982157114Sscottl 983157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 984157114Sscottl BUS_DMASYNC_POSTREAD); 985157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 986157114Sscottl 987233711Sambrisko max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io; 988157114Sscottl max_sectors_2 = ci->max_request_size; 989157114Sscottl sc->mfi_max_io = min(max_sectors_1, max_sectors_2); 990233711Sambrisko sc->disableOnlineCtrlReset = 991233711Sambrisko ci->properties.OnOffProperties.disableOnlineCtrlReset; 992157114Sscottl 993159806Spsout: 994159806Sps if (ci) 995159806Sps free(ci, M_MFIBUF); 996159806Sps if (cm) 997159806Sps mfi_release_command(cm); 998159806Sps mtx_unlock(&sc->mfi_io_lock); 999157114Sscottl return (error); 1000157114Sscottl} 1001157114Sscottl 1002157114Sscottlstatic int 1003159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state) 1004158737Sambrisko{ 1005159812Sps struct mfi_command *cm = NULL; 1006158737Sambrisko int error; 1007158737Sambrisko 1008233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1009159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO, 1010159806Sps (void **)log_state, sizeof(**log_state)); 1011159806Sps if (error) 1012159806Sps goto out; 1013159810Sps cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1014158737Sambrisko 1015158737Sambrisko if ((error = mfi_mapcmd(sc, cm)) != 0) { 1016159802Sps device_printf(sc->mfi_dev, "Failed to get log state\n"); 1017159806Sps goto out; 1018158737Sambrisko } 1019158737Sambrisko 1020158737Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1021158737Sambrisko BUS_DMASYNC_POSTREAD); 1022158737Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1023158737Sambrisko 1024159806Spsout: 1025159812Sps if (cm) 1026159812Sps mfi_release_command(cm); 1027233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1028158737Sambrisko 1029158737Sambrisko return (error); 1030158737Sambrisko} 1031158737Sambrisko 1032233711Sambriskoint 1033158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start) 1034158737Sambrisko{ 1035159806Sps struct mfi_evt_log_state *log_state = NULL; 1036158737Sambrisko union mfi_evt class_locale; 1037158737Sambrisko int error = 0; 1038158737Sambrisko uint32_t seq; 1039158737Sambrisko 1040158737Sambrisko class_locale.members.reserved = 0; 1041162118Sambrisko class_locale.members.locale = mfi_event_locale; 1042222589Semaste class_locale.members.evt_class = mfi_event_class; 1043158737Sambrisko 1044158737Sambrisko if (seq_start == 0) { 1045158737Sambrisko error = mfi_get_log_state(sc, &log_state); 1046233711Sambrisko sc->mfi_boot_seq_num = log_state->boot_seq_num; 1047159806Sps if (error) { 1048159806Sps if (log_state) 1049159806Sps free(log_state, M_MFIBUF); 1050158737Sambrisko return (error); 1051159806Sps } 1052180037Sjhb 1053180037Sjhb /* 1054180037Sjhb * Walk through any events that fired since the last 1055180037Sjhb * shutdown. 1056180037Sjhb */ 1057180037Sjhb mfi_parse_entries(sc, log_state->shutdown_seq_num, 1058180037Sjhb log_state->newest_seq_num); 1059180037Sjhb seq = log_state->newest_seq_num; 1060158737Sambrisko } else 1061158737Sambrisko seq = seq_start; 1062158737Sambrisko mfi_aen_register(sc, seq, class_locale.word); 1063159806Sps free(log_state, M_MFIBUF); 1064158737Sambrisko 1065158737Sambrisko return 0; 1066158737Sambrisko} 1067158737Sambrisko 1068233711Sambriskoint 1069159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm) 1070159811Sps{ 1071159811Sps 1072159811Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1073159811Sps cm->cm_complete = NULL; 1074159811Sps 1075170284Sambrisko 1076170284Sambrisko /* 1077170284Sambrisko * MegaCli can issue a DCMD of 0. In this case do nothing 1078170284Sambrisko * and return 0 to it as status 1079170284Sambrisko */ 1080170284Sambrisko if (cm->cm_frame->dcmd.opcode == 0) { 1081170284Sambrisko cm->cm_frame->header.cmd_status = MFI_STAT_OK; 1082170284Sambrisko cm->cm_error = 0; 1083170284Sambrisko return (cm->cm_error); 1084170284Sambrisko } 1085159811Sps mfi_enqueue_ready(cm); 1086159811Sps mfi_startio(sc); 1087170284Sambrisko if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0) 1088170284Sambrisko msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0); 1089170284Sambrisko return (cm->cm_error); 1090159811Sps} 1091159811Sps 1092157114Sscottlvoid 1093157114Sscottlmfi_free(struct mfi_softc *sc) 1094157114Sscottl{ 1095157114Sscottl struct mfi_command *cm; 1096157114Sscottl int i; 1097157114Sscottl 1098162619Sscottl callout_drain(&sc->mfi_watchdog_callout); 1099162619Sscottl 1100157114Sscottl if (sc->mfi_cdev != NULL) 1101157114Sscottl destroy_dev(sc->mfi_cdev); 1102157114Sscottl 1103157114Sscottl if (sc->mfi_total_cmds != 0) { 1104157114Sscottl for (i = 0; i < sc->mfi_total_cmds; i++) { 1105157114Sscottl cm = &sc->mfi_commands[i]; 1106157114Sscottl bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap); 1107157114Sscottl } 1108157114Sscottl free(sc->mfi_commands, M_MFIBUF); 1109157114Sscottl } 1110157114Sscottl 1111157114Sscottl if (sc->mfi_intr) 1112157114Sscottl bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr); 1113157114Sscottl if (sc->mfi_irq != NULL) 1114157114Sscottl bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid, 1115157114Sscottl sc->mfi_irq); 1116157114Sscottl 1117157114Sscottl if (sc->mfi_sense_busaddr != 0) 1118157114Sscottl bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap); 1119157114Sscottl if (sc->mfi_sense != NULL) 1120157114Sscottl bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense, 1121157114Sscottl sc->mfi_sense_dmamap); 1122157114Sscottl if (sc->mfi_sense_dmat != NULL) 1123157114Sscottl bus_dma_tag_destroy(sc->mfi_sense_dmat); 1124157114Sscottl 1125157114Sscottl if (sc->mfi_frames_busaddr != 0) 1126157114Sscottl bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap); 1127157114Sscottl if (sc->mfi_frames != NULL) 1128157114Sscottl bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames, 1129157114Sscottl sc->mfi_frames_dmamap); 1130157114Sscottl if (sc->mfi_frames_dmat != NULL) 1131157114Sscottl bus_dma_tag_destroy(sc->mfi_frames_dmat); 1132157114Sscottl 1133157114Sscottl if (sc->mfi_comms_busaddr != 0) 1134157114Sscottl bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap); 1135157114Sscottl if (sc->mfi_comms != NULL) 1136157114Sscottl bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms, 1137157114Sscottl sc->mfi_comms_dmamap); 1138157114Sscottl if (sc->mfi_comms_dmat != NULL) 1139157114Sscottl bus_dma_tag_destroy(sc->mfi_comms_dmat); 1140157114Sscottl 1141233711Sambrisko /* ThunderBolt contiguous memory free here */ 1142233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 1143233711Sambrisko if (sc->mfi_tb_busaddr != 0) 1144233711Sambrisko bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap); 1145233711Sambrisko if (sc->request_message_pool != NULL) 1146233711Sambrisko bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool, 1147233711Sambrisko sc->mfi_tb_dmamap); 1148233711Sambrisko if (sc->mfi_tb_dmat != NULL) 1149233711Sambrisko bus_dma_tag_destroy(sc->mfi_tb_dmat); 1150233711Sambrisko 1151233711Sambrisko /* Version buffer memory free */ 1152233711Sambrisko /* Start LSIP200113393 */ 1153233711Sambrisko if (sc->verbuf_h_busaddr != 0) 1154233711Sambrisko bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap); 1155233711Sambrisko if (sc->verbuf != NULL) 1156233711Sambrisko bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf, 1157233711Sambrisko sc->verbuf_h_dmamap); 1158233711Sambrisko if (sc->verbuf_h_dmat != NULL) 1159233711Sambrisko bus_dma_tag_destroy(sc->verbuf_h_dmat); 1160233711Sambrisko 1161233711Sambrisko /* End LSIP200113393 */ 1162233711Sambrisko /* ThunderBolt INIT packet memory Free */ 1163233711Sambrisko if (sc->mfi_tb_init_busaddr != 0) 1164233711Sambrisko bus_dmamap_unload(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap); 1165233711Sambrisko if (sc->mfi_tb_init != NULL) 1166233711Sambrisko bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init, 1167233711Sambrisko sc->mfi_tb_init_dmamap); 1168233711Sambrisko if (sc->mfi_tb_init_dmat != NULL) 1169233711Sambrisko bus_dma_tag_destroy(sc->mfi_tb_init_dmat); 1170233711Sambrisko 1171233711Sambrisko /* ThunderBolt IOC Init Desc memory free here */ 1172233711Sambrisko if (sc->mfi_tb_ioc_init_busaddr != 0) 1173233711Sambrisko bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat, 1174233711Sambrisko sc->mfi_tb_ioc_init_dmamap); 1175233711Sambrisko if (sc->mfi_tb_ioc_init_desc != NULL) 1176233711Sambrisko bus_dmamem_free(sc->mfi_tb_ioc_init_dmat, 1177233711Sambrisko sc->mfi_tb_ioc_init_desc, 1178233711Sambrisko sc->mfi_tb_ioc_init_dmamap); 1179233711Sambrisko if (sc->mfi_tb_ioc_init_dmat != NULL) 1180233711Sambrisko bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat); 1181233711Sambrisko for (int i = 0; i < sc->mfi_max_fw_cmds; i++) { 1182233711Sambrisko if (sc->mfi_cmd_pool_tbolt != NULL) { 1183233711Sambrisko if (sc->mfi_cmd_pool_tbolt[i] != NULL) { 1184233711Sambrisko free(sc->mfi_cmd_pool_tbolt[i], 1185233711Sambrisko M_MFIBUF); 1186233711Sambrisko sc->mfi_cmd_pool_tbolt[i] = NULL; 1187233711Sambrisko } 1188233711Sambrisko } 1189233711Sambrisko } 1190233711Sambrisko if (sc->mfi_cmd_pool_tbolt != NULL) { 1191233711Sambrisko free(sc->mfi_cmd_pool_tbolt, M_MFIBUF); 1192233711Sambrisko sc->mfi_cmd_pool_tbolt = NULL; 1193233711Sambrisko } 1194233711Sambrisko if (sc->request_desc_pool != NULL) { 1195233711Sambrisko free(sc->request_desc_pool, M_MFIBUF); 1196233711Sambrisko sc->request_desc_pool = NULL; 1197233711Sambrisko } 1198233711Sambrisko } 1199157114Sscottl if (sc->mfi_buffer_dmat != NULL) 1200157114Sscottl bus_dma_tag_destroy(sc->mfi_buffer_dmat); 1201157114Sscottl if (sc->mfi_parent_dmat != NULL) 1202157114Sscottl bus_dma_tag_destroy(sc->mfi_parent_dmat); 1203157114Sscottl 1204171821Sjhb if (mtx_initialized(&sc->mfi_io_lock)) { 1205157114Sscottl mtx_destroy(&sc->mfi_io_lock); 1206171821Sjhb sx_destroy(&sc->mfi_config_lock); 1207171821Sjhb } 1208157114Sscottl 1209157114Sscottl return; 1210157114Sscottl} 1211157114Sscottl 1212157114Sscottlstatic void 1213157114Sscottlmfi_startup(void *arg) 1214157114Sscottl{ 1215157114Sscottl struct mfi_softc *sc; 1216157114Sscottl 1217157114Sscottl sc = (struct mfi_softc *)arg; 1218157114Sscottl 1219157114Sscottl config_intrhook_disestablish(&sc->mfi_ich); 1220157114Sscottl 1221171980Sscottl sc->mfi_enable_intr(sc); 1222171821Sjhb sx_xlock(&sc->mfi_config_lock); 1223163398Sscottl mtx_lock(&sc->mfi_io_lock); 1224159811Sps mfi_ldprobe(sc); 1225233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) 1226233711Sambrisko mfi_syspdprobe(sc); 1227163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1228171821Sjhb sx_xunlock(&sc->mfi_config_lock); 1229157114Sscottl} 1230157114Sscottl 1231157114Sscottlstatic void 1232157114Sscottlmfi_intr(void *arg) 1233157114Sscottl{ 1234157114Sscottl struct mfi_softc *sc; 1235157114Sscottl struct mfi_command *cm; 1236171980Sscottl uint32_t pi, ci, context; 1237157114Sscottl 1238157114Sscottl sc = (struct mfi_softc *)arg; 1239157114Sscottl 1240171980Sscottl if (sc->mfi_check_clear_intr(sc)) 1241157114Sscottl return; 1242163398Sscottl 1243233711Sambriskorestart: 1244157114Sscottl pi = sc->mfi_comms->hw_pi; 1245157114Sscottl ci = sc->mfi_comms->hw_ci; 1246157114Sscottl mtx_lock(&sc->mfi_io_lock); 1247157114Sscottl while (ci != pi) { 1248157114Sscottl context = sc->mfi_comms->hw_reply_q[ci]; 1249170284Sambrisko if (context < sc->mfi_max_fw_cmds) { 1250170284Sambrisko cm = &sc->mfi_commands[context]; 1251170284Sambrisko mfi_remove_busy(cm); 1252170284Sambrisko cm->cm_error = 0; 1253170284Sambrisko mfi_complete(sc, cm); 1254170284Sambrisko } 1255162099Sscottl if (++ci == (sc->mfi_max_fw_cmds + 1)) { 1256157114Sscottl ci = 0; 1257157114Sscottl } 1258157114Sscottl } 1259157114Sscottl 1260157114Sscottl sc->mfi_comms->hw_ci = ci; 1261157114Sscottl 1262163398Sscottl /* Give defered I/O a chance to run */ 1263163398Sscottl if (sc->mfi_flags & MFI_FLAGS_QFRZN) 1264163398Sscottl sc->mfi_flags &= ~MFI_FLAGS_QFRZN; 1265163398Sscottl mfi_startio(sc); 1266163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1267163398Sscottl 1268233711Sambrisko /* 1269233711Sambrisko * Dummy read to flush the bus; this ensures that the indexes are up 1270233711Sambrisko * to date. Restart processing if more commands have come it. 1271233711Sambrisko */ 1272233711Sambrisko (void)sc->mfi_read_fw_status(sc); 1273233711Sambrisko if (pi != sc->mfi_comms->hw_pi) 1274233711Sambrisko goto restart; 1275233711Sambrisko 1276157114Sscottl return; 1277157114Sscottl} 1278157114Sscottl 1279157114Sscottlint 1280157114Sscottlmfi_shutdown(struct mfi_softc *sc) 1281157114Sscottl{ 1282157114Sscottl struct mfi_dcmd_frame *dcmd; 1283157114Sscottl struct mfi_command *cm; 1284157114Sscottl int error; 1285157114Sscottl 1286242681Sambrisko 1287242681Sambrisko if (sc->mfi_aen_cm) 1288242681Sambrisko sc->cm_aen_abort = 1; 1289242681Sambrisko if (sc->mfi_aen_cm != NULL) 1290242681Sambrisko mfi_abort(sc, &sc->mfi_aen_cm); 1291242681Sambrisko 1292242681Sambrisko if (sc->mfi_map_sync_cm) 1293242681Sambrisko sc->cm_map_abort = 1; 1294242681Sambrisko if (sc->mfi_map_sync_cm != NULL) 1295242681Sambrisko mfi_abort(sc, &sc->mfi_map_sync_cm); 1296242681Sambrisko 1297159806Sps mtx_lock(&sc->mfi_io_lock); 1298159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0); 1299163398Sscottl if (error) { 1300163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1301159806Sps return (error); 1302163398Sscottl } 1303157114Sscottl 1304157114Sscottl dcmd = &cm->cm_frame->dcmd; 1305157114Sscottl dcmd->header.flags = MFI_FRAME_DIR_NONE; 1306164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 1307164375Sscottl cm->cm_data = NULL; 1308157114Sscottl 1309164375Sscottl if ((error = mfi_mapcmd(sc, cm)) != 0) { 1310157114Sscottl device_printf(sc->mfi_dev, "Failed to shutdown controller\n"); 1311157114Sscottl } 1312157114Sscottl 1313159812Sps mfi_release_command(cm); 1314163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1315157114Sscottl return (error); 1316157114Sscottl} 1317157114Sscottl 1318157114Sscottlstatic void 1319233711Sambriskomfi_syspdprobe(struct mfi_softc *sc) 1320233711Sambrisko{ 1321233711Sambrisko struct mfi_frame_header *hdr; 1322233711Sambrisko struct mfi_command *cm = NULL; 1323233711Sambrisko struct mfi_pd_list *pdlist = NULL; 1324233711Sambrisko struct mfi_system_pd *syspd, *tmp; 1325242681Sambrisko struct mfi_system_pending *syspd_pend; 1326233711Sambrisko int error, i, found; 1327233711Sambrisko 1328233711Sambrisko sx_assert(&sc->mfi_config_lock, SA_XLOCKED); 1329233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1330233711Sambrisko /* Add SYSTEM PD's */ 1331233711Sambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY, 1332233711Sambrisko (void **)&pdlist, sizeof(*pdlist)); 1333235016Sambrisko if (error) { 1334233711Sambrisko device_printf(sc->mfi_dev, 1335233711Sambrisko "Error while forming SYSTEM PD list\n"); 1336233711Sambrisko goto out; 1337233711Sambrisko } 1338233711Sambrisko 1339233711Sambrisko cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1340233711Sambrisko cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST; 1341233711Sambrisko cm->cm_frame->dcmd.mbox[1] = 0; 1342233711Sambrisko if (mfi_mapcmd(sc, cm) != 0) { 1343233711Sambrisko device_printf(sc->mfi_dev, 1344233711Sambrisko "Failed to get syspd device listing\n"); 1345233711Sambrisko goto out; 1346233711Sambrisko } 1347233711Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap, 1348233711Sambrisko BUS_DMASYNC_POSTREAD); 1349233711Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1350233711Sambrisko hdr = &cm->cm_frame->header; 1351233711Sambrisko if (hdr->cmd_status != MFI_STAT_OK) { 1352233711Sambrisko device_printf(sc->mfi_dev, 1353233711Sambrisko "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status); 1354233711Sambrisko goto out; 1355233711Sambrisko } 1356233711Sambrisko /* Get each PD and add it to the system */ 1357233711Sambrisko for (i = 0; i < pdlist->count; i++) { 1358233711Sambrisko if (pdlist->addr[i].device_id == 1359233711Sambrisko pdlist->addr[i].encl_device_id) 1360233711Sambrisko continue; 1361233711Sambrisko found = 0; 1362233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { 1363233711Sambrisko if (syspd->pd_id == pdlist->addr[i].device_id) 1364233711Sambrisko found = 1; 1365233711Sambrisko } 1366242681Sambrisko TAILQ_FOREACH(syspd_pend, &sc->mfi_syspd_pend_tqh, pd_link) { 1367242681Sambrisko if (syspd_pend->pd_id == pdlist->addr[i].device_id) 1368242681Sambrisko found = 1; 1369242681Sambrisko } 1370233711Sambrisko if (found == 0) 1371233711Sambrisko mfi_add_sys_pd(sc, pdlist->addr[i].device_id); 1372233711Sambrisko } 1373233711Sambrisko /* Delete SYSPD's whose state has been changed */ 1374233711Sambrisko TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) { 1375233711Sambrisko found = 0; 1376233711Sambrisko for (i = 0; i < pdlist->count; i++) { 1377233711Sambrisko if (syspd->pd_id == pdlist->addr[i].device_id) 1378233711Sambrisko found = 1; 1379233711Sambrisko } 1380233711Sambrisko if (found == 0) { 1381233711Sambrisko printf("DELETE\n"); 1382233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1383233711Sambrisko mtx_lock(&Giant); 1384233711Sambrisko device_delete_child(sc->mfi_dev, syspd->pd_dev); 1385233711Sambrisko mtx_unlock(&Giant); 1386233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1387233711Sambrisko } 1388233711Sambrisko } 1389233711Sambriskoout: 1390233711Sambrisko if (pdlist) 1391233711Sambrisko free(pdlist, M_MFIBUF); 1392233711Sambrisko if (cm) 1393233711Sambrisko mfi_release_command(cm); 1394233711Sambrisko 1395233711Sambrisko return; 1396233711Sambrisko} 1397233711Sambrisko 1398233711Sambriskostatic void 1399159811Spsmfi_ldprobe(struct mfi_softc *sc) 1400157114Sscottl{ 1401159811Sps struct mfi_frame_header *hdr; 1402159811Sps struct mfi_command *cm = NULL; 1403159811Sps struct mfi_ld_list *list = NULL; 1404171821Sjhb struct mfi_disk *ld; 1405242681Sambrisko struct mfi_disk_pending *ld_pend; 1406159811Sps int error, i; 1407157114Sscottl 1408171821Sjhb sx_assert(&sc->mfi_config_lock, SA_XLOCKED); 1409163398Sscottl mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1410163398Sscottl 1411159811Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST, 1412159811Sps (void **)&list, sizeof(*list)); 1413159811Sps if (error) 1414159811Sps goto out; 1415159811Sps 1416159811Sps cm->cm_flags = MFI_CMD_DATAIN; 1417159811Sps if (mfi_wait_command(sc, cm) != 0) { 1418159811Sps device_printf(sc->mfi_dev, "Failed to get device listing\n"); 1419159811Sps goto out; 1420157114Sscottl } 1421157114Sscottl 1422157114Sscottl hdr = &cm->cm_frame->header; 1423159811Sps if (hdr->cmd_status != MFI_STAT_OK) { 1424159811Sps device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n", 1425159811Sps hdr->cmd_status); 1426159811Sps goto out; 1427157114Sscottl } 1428157114Sscottl 1429171821Sjhb for (i = 0; i < list->ld_count; i++) { 1430171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 1431171821Sjhb if (ld->ld_id == list->ld_list[i].ld.v.target_id) 1432171821Sjhb goto skip_add; 1433171821Sjhb } 1434242681Sambrisko TAILQ_FOREACH(ld_pend, &sc->mfi_ld_pend_tqh, ld_link) { 1435242681Sambrisko if (ld_pend->ld_id == list->ld_list[i].ld.v.target_id) 1436242681Sambrisko goto skip_add; 1437242681Sambrisko } 1438163398Sscottl mfi_add_ld(sc, list->ld_list[i].ld.v.target_id); 1439171821Sjhb skip_add:; 1440171821Sjhb } 1441159811Spsout: 1442159811Sps if (list) 1443159811Sps free(list, M_MFIBUF); 1444159811Sps if (cm) 1445157114Sscottl mfi_release_command(cm); 1446163398Sscottl 1447159811Sps return; 1448157114Sscottl} 1449157114Sscottl 1450180038Sjhb/* 1451180038Sjhb * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If 1452180038Sjhb * the bits in 24-31 are all set, then it is the number of seconds since 1453180038Sjhb * boot. 1454180038Sjhb */ 1455180038Sjhbstatic const char * 1456180038Sjhbformat_timestamp(uint32_t timestamp) 1457158737Sambrisko{ 1458180038Sjhb static char buffer[32]; 1459180038Sjhb 1460180038Sjhb if ((timestamp & 0xff000000) == 0xff000000) 1461180038Sjhb snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & 1462180038Sjhb 0x00ffffff); 1463180038Sjhb else 1464180038Sjhb snprintf(buffer, sizeof(buffer), "%us", timestamp); 1465180038Sjhb return (buffer); 1466180038Sjhb} 1467180038Sjhb 1468180038Sjhbstatic const char * 1469180038Sjhbformat_class(int8_t class) 1470180038Sjhb{ 1471180038Sjhb static char buffer[6]; 1472180038Sjhb 1473180038Sjhb switch (class) { 1474180038Sjhb case MFI_EVT_CLASS_DEBUG: 1475180038Sjhb return ("debug"); 1476180038Sjhb case MFI_EVT_CLASS_PROGRESS: 1477180038Sjhb return ("progress"); 1478180038Sjhb case MFI_EVT_CLASS_INFO: 1479180038Sjhb return ("info"); 1480180038Sjhb case MFI_EVT_CLASS_WARNING: 1481180038Sjhb return ("WARN"); 1482180038Sjhb case MFI_EVT_CLASS_CRITICAL: 1483180038Sjhb return ("CRIT"); 1484180038Sjhb case MFI_EVT_CLASS_FATAL: 1485180038Sjhb return ("FATAL"); 1486180038Sjhb case MFI_EVT_CLASS_DEAD: 1487180038Sjhb return ("DEAD"); 1488158737Sambrisko default: 1489180038Sjhb snprintf(buffer, sizeof(buffer), "%d", class); 1490180038Sjhb return (buffer); 1491158737Sambrisko } 1492158737Sambrisko} 1493158737Sambrisko 1494180038Sjhbstatic void 1495180038Sjhbmfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) 1496180038Sjhb{ 1497233711Sambrisko struct mfi_system_pd *syspd = NULL; 1498180038Sjhb 1499200238Sjkim device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq, 1500222589Semaste format_timestamp(detail->time), detail->evt_class.members.locale, 1501233711Sambrisko format_class(detail->evt_class.members.evt_class), 1502233711Sambrisko detail->description); 1503233711Sambrisko 1504233711Sambrisko /* Don't act on old AEN's or while shutting down */ 1505233711Sambrisko if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching) 1506233711Sambrisko return; 1507233711Sambrisko 1508233711Sambrisko switch (detail->arg_type) { 1509233711Sambrisko case MR_EVT_ARGS_NONE: 1510233711Sambrisko if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) { 1511233711Sambrisko device_printf(sc->mfi_dev, "HostBus scan raised\n"); 1512233711Sambrisko if (mfi_detect_jbod_change) { 1513233711Sambrisko /* 1514233711Sambrisko * Probe for new SYSPD's and Delete 1515233711Sambrisko * invalid SYSPD's 1516233711Sambrisko */ 1517233711Sambrisko sx_xlock(&sc->mfi_config_lock); 1518233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1519233711Sambrisko mfi_syspdprobe(sc); 1520233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1521233711Sambrisko sx_xunlock(&sc->mfi_config_lock); 1522233711Sambrisko } 1523233711Sambrisko } 1524233711Sambrisko break; 1525233711Sambrisko case MR_EVT_ARGS_LD_STATE: 1526233711Sambrisko /* During load time driver reads all the events starting 1527233711Sambrisko * from the one that has been logged after shutdown. Avoid 1528233711Sambrisko * these old events. 1529233711Sambrisko */ 1530233711Sambrisko if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) { 1531233711Sambrisko /* Remove the LD */ 1532233711Sambrisko struct mfi_disk *ld; 1533233711Sambrisko TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 1534233711Sambrisko if (ld->ld_id == 1535233711Sambrisko detail->args.ld_state.ld.target_id) 1536233711Sambrisko break; 1537233711Sambrisko } 1538233711Sambrisko /* 1539233711Sambrisko Fix: for kernel panics when SSCD is removed 1540233711Sambrisko KASSERT(ld != NULL, ("volume dissappeared")); 1541233711Sambrisko */ 1542233711Sambrisko if (ld != NULL) { 1543233711Sambrisko mtx_lock(&Giant); 1544233711Sambrisko device_delete_child(sc->mfi_dev, ld->ld_dev); 1545233711Sambrisko mtx_unlock(&Giant); 1546233711Sambrisko } 1547233711Sambrisko } 1548233711Sambrisko break; 1549233711Sambrisko case MR_EVT_ARGS_PD: 1550233711Sambrisko if (detail->code == MR_EVT_PD_REMOVED) { 1551233711Sambrisko if (mfi_detect_jbod_change) { 1552233711Sambrisko /* 1553233711Sambrisko * If the removed device is a SYSPD then 1554233711Sambrisko * delete it 1555233711Sambrisko */ 1556233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, 1557233711Sambrisko pd_link) { 1558233711Sambrisko if (syspd->pd_id == 1559233711Sambrisko detail->args.pd.device_id) { 1560233711Sambrisko mtx_lock(&Giant); 1561233711Sambrisko device_delete_child( 1562233711Sambrisko sc->mfi_dev, 1563233711Sambrisko syspd->pd_dev); 1564233711Sambrisko mtx_unlock(&Giant); 1565233711Sambrisko break; 1566233711Sambrisko } 1567233711Sambrisko } 1568233711Sambrisko } 1569233711Sambrisko } 1570233711Sambrisko if (detail->code == MR_EVT_PD_INSERTED) { 1571233711Sambrisko if (mfi_detect_jbod_change) { 1572233711Sambrisko /* Probe for new SYSPD's */ 1573233711Sambrisko sx_xlock(&sc->mfi_config_lock); 1574233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1575233711Sambrisko mfi_syspdprobe(sc); 1576233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1577233711Sambrisko sx_xunlock(&sc->mfi_config_lock); 1578233711Sambrisko } 1579233711Sambrisko } 1580233711Sambrisko break; 1581233711Sambrisko } 1582180038Sjhb} 1583180038Sjhb 1584233711Sambriskostatic void 1585233711Sambriskomfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) 1586233711Sambrisko{ 1587233711Sambrisko struct mfi_evt_queue_elm *elm; 1588233711Sambrisko 1589233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1590233711Sambrisko elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO); 1591233711Sambrisko if (elm == NULL) 1592233711Sambrisko return; 1593233711Sambrisko memcpy(&elm->detail, detail, sizeof(*detail)); 1594233711Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link); 1595233711Sambrisko taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task); 1596233711Sambrisko} 1597233711Sambrisko 1598233711Sambriskostatic void 1599233711Sambriskomfi_handle_evt(void *context, int pending) 1600233711Sambrisko{ 1601233711Sambrisko TAILQ_HEAD(,mfi_evt_queue_elm) queue; 1602233711Sambrisko struct mfi_softc *sc; 1603233711Sambrisko struct mfi_evt_queue_elm *elm; 1604233711Sambrisko 1605233711Sambrisko sc = context; 1606233711Sambrisko TAILQ_INIT(&queue); 1607233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1608233711Sambrisko TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link); 1609233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1610233711Sambrisko while ((elm = TAILQ_FIRST(&queue)) != NULL) { 1611233711Sambrisko TAILQ_REMOVE(&queue, elm, link); 1612233711Sambrisko mfi_decode_evt(sc, &elm->detail); 1613233711Sambrisko free(elm, M_MFIBUF); 1614233711Sambrisko } 1615233711Sambrisko} 1616233711Sambrisko 1617157114Sscottlstatic int 1618158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale) 1619158737Sambrisko{ 1620158737Sambrisko struct mfi_command *cm; 1621158737Sambrisko struct mfi_dcmd_frame *dcmd; 1622158737Sambrisko union mfi_evt current_aen, prior_aen; 1623159806Sps struct mfi_evt_detail *ed = NULL; 1624163398Sscottl int error = 0; 1625158737Sambrisko 1626158737Sambrisko current_aen.word = locale; 1627158737Sambrisko if (sc->mfi_aen_cm != NULL) { 1628158737Sambrisko prior_aen.word = 1629158737Sambrisko ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1]; 1630222589Semaste if (prior_aen.members.evt_class <= current_aen.members.evt_class && 1631158737Sambrisko !((prior_aen.members.locale & current_aen.members.locale) 1632158737Sambrisko ^current_aen.members.locale)) { 1633158737Sambrisko return (0); 1634158737Sambrisko } else { 1635158737Sambrisko prior_aen.members.locale |= current_aen.members.locale; 1636222589Semaste if (prior_aen.members.evt_class 1637222589Semaste < current_aen.members.evt_class) 1638222589Semaste current_aen.members.evt_class = 1639222589Semaste prior_aen.members.evt_class; 1640242681Sambrisko mfi_abort(sc, &sc->mfi_aen_cm); 1641158737Sambrisko } 1642158737Sambrisko } 1643158737Sambrisko 1644233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1645159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT, 1646159806Sps (void **)&ed, sizeof(*ed)); 1647233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1648163398Sscottl if (error) { 1649163398Sscottl goto out; 1650163398Sscottl } 1651158737Sambrisko 1652158737Sambrisko dcmd = &cm->cm_frame->dcmd; 1653158737Sambrisko ((uint32_t *)&dcmd->mbox)[0] = seq; 1654158737Sambrisko ((uint32_t *)&dcmd->mbox)[1] = locale; 1655158737Sambrisko cm->cm_flags = MFI_CMD_DATAIN; 1656158737Sambrisko cm->cm_complete = mfi_aen_complete; 1657158737Sambrisko 1658233711Sambrisko sc->last_seq_num = seq; 1659158737Sambrisko sc->mfi_aen_cm = cm; 1660158737Sambrisko 1661233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1662158737Sambrisko mfi_enqueue_ready(cm); 1663158737Sambrisko mfi_startio(sc); 1664233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1665158737Sambrisko 1666163398Sscottlout: 1667163398Sscottl return (error); 1668158737Sambrisko} 1669158737Sambrisko 1670158737Sambriskostatic void 1671158737Sambriskomfi_aen_complete(struct mfi_command *cm) 1672158737Sambrisko{ 1673158737Sambrisko struct mfi_frame_header *hdr; 1674158737Sambrisko struct mfi_softc *sc; 1675158737Sambrisko struct mfi_evt_detail *detail; 1676163398Sscottl struct mfi_aen *mfi_aen_entry, *tmp; 1677158737Sambrisko int seq = 0, aborted = 0; 1678158737Sambrisko 1679158737Sambrisko sc = cm->cm_sc; 1680233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1681233711Sambrisko 1682158737Sambrisko hdr = &cm->cm_frame->header; 1683158737Sambrisko 1684158737Sambrisko if (sc->mfi_aen_cm == NULL) 1685158737Sambrisko return; 1686158737Sambrisko 1687235014Sambrisko if (sc->cm_aen_abort || 1688224039Sjhb hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 1689235014Sambrisko sc->cm_aen_abort = 0; 1690158737Sambrisko aborted = 1; 1691158737Sambrisko } else { 1692158737Sambrisko sc->mfi_aen_triggered = 1; 1693163398Sscottl if (sc->mfi_poll_waiting) { 1694163398Sscottl sc->mfi_poll_waiting = 0; 1695158737Sambrisko selwakeup(&sc->mfi_select); 1696163398Sscottl } 1697158737Sambrisko detail = cm->cm_data; 1698233711Sambrisko mfi_queue_evt(sc, detail); 1699158737Sambrisko seq = detail->seq + 1; 1700233711Sambrisko TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, 1701233711Sambrisko tmp) { 1702158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 1703158737Sambrisko aen_link); 1704163398Sscottl PROC_LOCK(mfi_aen_entry->p); 1705225617Skmacy kern_psignal(mfi_aen_entry->p, SIGIO); 1706163398Sscottl PROC_UNLOCK(mfi_aen_entry->p); 1707158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 1708158737Sambrisko } 1709158737Sambrisko } 1710158737Sambrisko 1711158737Sambrisko free(cm->cm_data, M_MFIBUF); 1712158737Sambrisko sc->mfi_aen_cm = NULL; 1713158737Sambrisko wakeup(&sc->mfi_aen_cm); 1714158737Sambrisko mfi_release_command(cm); 1715158737Sambrisko 1716158737Sambrisko /* set it up again so the driver can catch more events */ 1717158737Sambrisko if (!aborted) { 1718233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1719158737Sambrisko mfi_aen_setup(sc, seq); 1720233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1721158737Sambrisko } 1722158737Sambrisko} 1723158737Sambrisko 1724180037Sjhb#define MAX_EVENTS 15 1725180037Sjhb 1726158737Sambriskostatic int 1727180037Sjhbmfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) 1728158737Sambrisko{ 1729158737Sambrisko struct mfi_command *cm; 1730158737Sambrisko struct mfi_dcmd_frame *dcmd; 1731162118Sambrisko struct mfi_evt_list *el; 1732180037Sjhb union mfi_evt class_locale; 1733180037Sjhb int error, i, seq, size; 1734158737Sambrisko 1735180037Sjhb class_locale.members.reserved = 0; 1736180037Sjhb class_locale.members.locale = mfi_event_locale; 1737222589Semaste class_locale.members.evt_class = mfi_event_class; 1738158737Sambrisko 1739162118Sambrisko size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) 1740162118Sambrisko * (MAX_EVENTS - 1); 1741162118Sambrisko el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO); 1742180037Sjhb if (el == NULL) 1743158737Sambrisko return (ENOMEM); 1744158737Sambrisko 1745180037Sjhb for (seq = start_seq;;) { 1746233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1747180037Sjhb if ((cm = mfi_dequeue_free(sc)) == NULL) { 1748180037Sjhb free(el, M_MFIBUF); 1749233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1750180037Sjhb return (EBUSY); 1751180037Sjhb } 1752233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1753158737Sambrisko 1754180037Sjhb dcmd = &cm->cm_frame->dcmd; 1755180037Sjhb bzero(dcmd->mbox, MFI_MBOX_SIZE); 1756180037Sjhb dcmd->header.cmd = MFI_CMD_DCMD; 1757180037Sjhb dcmd->header.timeout = 0; 1758180037Sjhb dcmd->header.data_len = size; 1759180037Sjhb dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET; 1760180037Sjhb ((uint32_t *)&dcmd->mbox)[0] = seq; 1761180037Sjhb ((uint32_t *)&dcmd->mbox)[1] = class_locale.word; 1762180037Sjhb cm->cm_sg = &dcmd->sgl; 1763180037Sjhb cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 1764180037Sjhb cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1765180037Sjhb cm->cm_data = el; 1766180037Sjhb cm->cm_len = size; 1767180037Sjhb 1768233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1769180037Sjhb if ((error = mfi_mapcmd(sc, cm)) != 0) { 1770180037Sjhb device_printf(sc->mfi_dev, 1771180037Sjhb "Failed to get controller entries\n"); 1772180037Sjhb mfi_release_command(cm); 1773233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1774180037Sjhb break; 1775180037Sjhb } 1776180037Sjhb 1777233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1778180037Sjhb bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1779180037Sjhb BUS_DMASYNC_POSTREAD); 1780180037Sjhb bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1781180037Sjhb 1782180037Sjhb if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) { 1783233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1784180037Sjhb mfi_release_command(cm); 1785233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1786180037Sjhb break; 1787180037Sjhb } 1788180037Sjhb if (dcmd->header.cmd_status != MFI_STAT_OK) { 1789180037Sjhb device_printf(sc->mfi_dev, 1790180037Sjhb "Error %d fetching controller entries\n", 1791180037Sjhb dcmd->header.cmd_status); 1792233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1793180037Sjhb mfi_release_command(cm); 1794233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1795180037Sjhb break; 1796180037Sjhb } 1797233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1798158737Sambrisko mfi_release_command(cm); 1799233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1800158737Sambrisko 1801162473Sambrisko for (i = 0; i < el->count; i++) { 1802180037Sjhb /* 1803180037Sjhb * If this event is newer than 'stop_seq' then 1804180037Sjhb * break out of the loop. Note that the log 1805180037Sjhb * is a circular buffer so we have to handle 1806180037Sjhb * the case that our stop point is earlier in 1807180037Sjhb * the buffer than our start point. 1808180037Sjhb */ 1809180037Sjhb if (el->event[i].seq >= stop_seq) { 1810180037Sjhb if (start_seq <= stop_seq) 1811180037Sjhb break; 1812180037Sjhb else if (el->event[i].seq < start_seq) 1813180037Sjhb break; 1814180037Sjhb } 1815233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1816233711Sambrisko mfi_queue_evt(sc, &el->event[i]); 1817233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1818162473Sambrisko } 1819180037Sjhb seq = el->event[el->count - 1].seq + 1; 1820162118Sambrisko } 1821158737Sambrisko 1822180037Sjhb free(el, M_MFIBUF); 1823158737Sambrisko return (0); 1824158737Sambrisko} 1825158737Sambrisko 1826158737Sambriskostatic int 1827159811Spsmfi_add_ld(struct mfi_softc *sc, int id) 1828157114Sscottl{ 1829157114Sscottl struct mfi_command *cm; 1830159811Sps struct mfi_dcmd_frame *dcmd = NULL; 1831159811Sps struct mfi_ld_info *ld_info = NULL; 1832242681Sambrisko struct mfi_disk_pending *ld_pend; 1833159811Sps int error; 1834157114Sscottl 1835159811Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1836159811Sps 1837242681Sambrisko ld_pend = malloc(sizeof(*ld_pend), M_MFIBUF, M_NOWAIT | M_ZERO); 1838242681Sambrisko if (ld_pend != NULL) { 1839242681Sambrisko ld_pend->ld_id = id; 1840242681Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_ld_pend_tqh, ld_pend, ld_link); 1841242681Sambrisko } 1842242681Sambrisko 1843159811Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO, 1844159811Sps (void **)&ld_info, sizeof(*ld_info)); 1845159811Sps if (error) { 1846159811Sps device_printf(sc->mfi_dev, 1847159811Sps "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error); 1848159811Sps if (ld_info) 1849159811Sps free(ld_info, M_MFIBUF); 1850159811Sps return (error); 1851157624Sscottl } 1852159811Sps cm->cm_flags = MFI_CMD_DATAIN; 1853159811Sps dcmd = &cm->cm_frame->dcmd; 1854159811Sps dcmd->mbox[0] = id; 1855160052Sambrisko if (mfi_wait_command(sc, cm) != 0) { 1856160052Sambrisko device_printf(sc->mfi_dev, 1857160052Sambrisko "Failed to get logical drive: %d\n", id); 1858160052Sambrisko free(ld_info, M_MFIBUF); 1859160052Sambrisko return (0); 1860160052Sambrisko } 1861233711Sambrisko if (ld_info->ld_config.params.isSSCD != 1) 1862233711Sambrisko mfi_add_ld_complete(cm); 1863233711Sambrisko else { 1864233711Sambrisko mfi_release_command(cm); 1865233711Sambrisko if (ld_info) /* SSCD drives ld_info free here */ 1866233711Sambrisko free(ld_info, M_MFIBUF); 1867233711Sambrisko } 1868157114Sscottl return (0); 1869157114Sscottl} 1870157114Sscottl 1871157114Sscottlstatic void 1872159811Spsmfi_add_ld_complete(struct mfi_command *cm) 1873157114Sscottl{ 1874157114Sscottl struct mfi_frame_header *hdr; 1875159811Sps struct mfi_ld_info *ld_info; 1876157114Sscottl struct mfi_softc *sc; 1877159811Sps device_t child; 1878157114Sscottl 1879157114Sscottl sc = cm->cm_sc; 1880157114Sscottl hdr = &cm->cm_frame->header; 1881159811Sps ld_info = cm->cm_private; 1882157114Sscottl 1883242681Sambrisko if (sc->cm_map_abort || hdr->cmd_status != MFI_STAT_OK) { 1884159811Sps free(ld_info, M_MFIBUF); 1885242681Sambrisko wakeup(&sc->mfi_map_sync_cm); 1886157114Sscottl mfi_release_command(cm); 1887157114Sscottl return; 1888157114Sscottl } 1889242681Sambrisko wakeup(&sc->mfi_map_sync_cm); 1890157114Sscottl mfi_release_command(cm); 1891157114Sscottl 1892169611Sscottl mtx_unlock(&sc->mfi_io_lock); 1893196403Sjhb mtx_lock(&Giant); 1894157114Sscottl if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) { 1895157114Sscottl device_printf(sc->mfi_dev, "Failed to add logical disk\n"); 1896159811Sps free(ld_info, M_MFIBUF); 1897196403Sjhb mtx_unlock(&Giant); 1898169611Sscottl mtx_lock(&sc->mfi_io_lock); 1899159811Sps return; 1900157114Sscottl } 1901157114Sscottl 1902169451Sscottl device_set_ivars(child, ld_info); 1903157114Sscottl device_set_desc(child, "MFI Logical Disk"); 1904157114Sscottl bus_generic_attach(sc->mfi_dev); 1905196403Sjhb mtx_unlock(&Giant); 1906157114Sscottl mtx_lock(&sc->mfi_io_lock); 1907157114Sscottl} 1908163399Sscottl 1909233711Sambriskostatic int mfi_add_sys_pd(struct mfi_softc *sc, int id) 1910233711Sambrisko{ 1911233711Sambrisko struct mfi_command *cm; 1912233711Sambrisko struct mfi_dcmd_frame *dcmd = NULL; 1913233711Sambrisko struct mfi_pd_info *pd_info = NULL; 1914242681Sambrisko struct mfi_system_pending *syspd_pend; 1915233711Sambrisko int error; 1916233711Sambrisko 1917233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1918233711Sambrisko 1919242681Sambrisko syspd_pend = malloc(sizeof(*syspd_pend), M_MFIBUF, M_NOWAIT | M_ZERO); 1920242681Sambrisko if (syspd_pend != NULL) { 1921242681Sambrisko syspd_pend->pd_id = id; 1922242681Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_syspd_pend_tqh, syspd_pend, pd_link); 1923242681Sambrisko } 1924242681Sambrisko 1925233711Sambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO, 1926233711Sambrisko (void **)&pd_info, sizeof(*pd_info)); 1927233711Sambrisko if (error) { 1928233711Sambrisko device_printf(sc->mfi_dev, 1929233711Sambrisko "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n", 1930233711Sambrisko error); 1931233711Sambrisko if (pd_info) 1932233711Sambrisko free(pd_info, M_MFIBUF); 1933233711Sambrisko return (error); 1934233711Sambrisko } 1935233711Sambrisko cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1936233711Sambrisko dcmd = &cm->cm_frame->dcmd; 1937233711Sambrisko dcmd->mbox[0]=id; 1938233711Sambrisko dcmd->header.scsi_status = 0; 1939233711Sambrisko dcmd->header.pad0 = 0; 1940233711Sambrisko if (mfi_mapcmd(sc, cm) != 0) { 1941233711Sambrisko device_printf(sc->mfi_dev, 1942233711Sambrisko "Failed to get physical drive info %d\n", id); 1943233711Sambrisko free(pd_info, M_MFIBUF); 1944233711Sambrisko return (0); 1945233711Sambrisko } 1946233711Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1947233711Sambrisko BUS_DMASYNC_POSTREAD); 1948233711Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1949233711Sambrisko mfi_add_sys_pd_complete(cm); 1950233711Sambrisko return (0); 1951233711Sambrisko} 1952233711Sambrisko 1953233711Sambriskostatic void 1954233711Sambriskomfi_add_sys_pd_complete(struct mfi_command *cm) 1955233711Sambrisko{ 1956233711Sambrisko struct mfi_frame_header *hdr; 1957233711Sambrisko struct mfi_pd_info *pd_info; 1958233711Sambrisko struct mfi_softc *sc; 1959233711Sambrisko device_t child; 1960233711Sambrisko 1961233711Sambrisko sc = cm->cm_sc; 1962233711Sambrisko hdr = &cm->cm_frame->header; 1963233711Sambrisko pd_info = cm->cm_private; 1964233711Sambrisko 1965233711Sambrisko if (hdr->cmd_status != MFI_STAT_OK) { 1966233711Sambrisko free(pd_info, M_MFIBUF); 1967233711Sambrisko mfi_release_command(cm); 1968233711Sambrisko return; 1969233711Sambrisko } 1970233711Sambrisko if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) { 1971233711Sambrisko device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n", 1972233711Sambrisko pd_info->ref.v.device_id); 1973233711Sambrisko free(pd_info, M_MFIBUF); 1974233711Sambrisko mfi_release_command(cm); 1975233711Sambrisko return; 1976233711Sambrisko } 1977233711Sambrisko mfi_release_command(cm); 1978233711Sambrisko 1979233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1980233711Sambrisko mtx_lock(&Giant); 1981233711Sambrisko if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) { 1982233711Sambrisko device_printf(sc->mfi_dev, "Failed to add system pd\n"); 1983233711Sambrisko free(pd_info, M_MFIBUF); 1984233711Sambrisko mtx_unlock(&Giant); 1985233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1986233711Sambrisko return; 1987233711Sambrisko } 1988233711Sambrisko 1989233711Sambrisko device_set_ivars(child, pd_info); 1990233711Sambrisko device_set_desc(child, "MFI System PD"); 1991233711Sambrisko bus_generic_attach(sc->mfi_dev); 1992233711Sambrisko mtx_unlock(&Giant); 1993233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1994233711Sambrisko} 1995235016Sambrisko 1996157114Sscottlstatic struct mfi_command * 1997157114Sscottlmfi_bio_command(struct mfi_softc *sc) 1998157114Sscottl{ 1999157114Sscottl struct bio *bio; 2000233711Sambrisko struct mfi_command *cm = NULL; 2001157114Sscottl 2002233711Sambrisko /*reserving two commands to avoid starvation for IOCTL*/ 2003235016Sambrisko if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) { 2004157114Sscottl return (NULL); 2005233711Sambrisko } 2006157114Sscottl if ((bio = mfi_dequeue_bio(sc)) == NULL) { 2007157114Sscottl return (NULL); 2008157114Sscottl } 2009233711Sambrisko if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) { 2010233711Sambrisko cm = mfi_build_ldio(sc, bio); 2011233711Sambrisko } else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) { 2012233711Sambrisko cm = mfi_build_syspdio(sc, bio); 2013233711Sambrisko } 2014233711Sambrisko if (!cm) 2015233711Sambrisko mfi_enqueue_bio(sc, bio); 2016233711Sambrisko return cm; 2017233711Sambrisko} 2018242497Sdelphij 2019242681Sambrisko/* 2020242681Sambrisko * mostly copied from cam/scsi/scsi_all.c:scsi_read_write 2021242681Sambrisko */ 2022242681Sambrisko 2023242681Sambriskoint 2024242681Sambriskomfi_build_cdb(int readop, uint8_t byte2, u_int64_t lba, u_int32_t block_count, uint8_t *cdb) 2025242497Sdelphij{ 2026242497Sdelphij int cdb_len; 2027242497Sdelphij 2028242497Sdelphij if (((lba & 0x1fffff) == lba) 2029242497Sdelphij && ((block_count & 0xff) == block_count) 2030242497Sdelphij && (byte2 == 0)) { 2031242497Sdelphij /* We can fit in a 6 byte cdb */ 2032242497Sdelphij struct scsi_rw_6 *scsi_cmd; 2033242497Sdelphij 2034242681Sambrisko scsi_cmd = (struct scsi_rw_6 *)cdb; 2035242497Sdelphij scsi_cmd->opcode = readop ? READ_6 : WRITE_6; 2036242497Sdelphij scsi_ulto3b(lba, scsi_cmd->addr); 2037242497Sdelphij scsi_cmd->length = block_count & 0xff; 2038242497Sdelphij scsi_cmd->control = 0; 2039242497Sdelphij cdb_len = sizeof(*scsi_cmd); 2040242497Sdelphij } else if (((block_count & 0xffff) == block_count) && ((lba & 0xffffffff) == lba)) { 2041242497Sdelphij /* Need a 10 byte CDB */ 2042242497Sdelphij struct scsi_rw_10 *scsi_cmd; 2043242497Sdelphij 2044242681Sambrisko scsi_cmd = (struct scsi_rw_10 *)cdb; 2045242497Sdelphij scsi_cmd->opcode = readop ? READ_10 : WRITE_10; 2046242497Sdelphij scsi_cmd->byte2 = byte2; 2047242497Sdelphij scsi_ulto4b(lba, scsi_cmd->addr); 2048242497Sdelphij scsi_cmd->reserved = 0; 2049242497Sdelphij scsi_ulto2b(block_count, scsi_cmd->length); 2050242497Sdelphij scsi_cmd->control = 0; 2051242497Sdelphij cdb_len = sizeof(*scsi_cmd); 2052242497Sdelphij } else if (((block_count & 0xffffffff) == block_count) && 2053242497Sdelphij ((lba & 0xffffffff) == lba)) { 2054242497Sdelphij /* Block count is too big for 10 byte CDB use a 12 byte CDB */ 2055242497Sdelphij struct scsi_rw_12 *scsi_cmd; 2056242497Sdelphij 2057242681Sambrisko scsi_cmd = (struct scsi_rw_12 *)cdb; 2058242497Sdelphij scsi_cmd->opcode = readop ? READ_12 : WRITE_12; 2059242497Sdelphij scsi_cmd->byte2 = byte2; 2060242497Sdelphij scsi_ulto4b(lba, scsi_cmd->addr); 2061242497Sdelphij scsi_cmd->reserved = 0; 2062242497Sdelphij scsi_ulto4b(block_count, scsi_cmd->length); 2063242497Sdelphij scsi_cmd->control = 0; 2064242497Sdelphij cdb_len = sizeof(*scsi_cmd); 2065242497Sdelphij } else { 2066242497Sdelphij /* 2067242497Sdelphij * 16 byte CDB. We'll only get here if the LBA is larger 2068242497Sdelphij * than 2^32 2069242497Sdelphij */ 2070242497Sdelphij struct scsi_rw_16 *scsi_cmd; 2071242497Sdelphij 2072242681Sambrisko scsi_cmd = (struct scsi_rw_16 *)cdb; 2073242497Sdelphij scsi_cmd->opcode = readop ? READ_16 : WRITE_16; 2074242497Sdelphij scsi_cmd->byte2 = byte2; 2075242497Sdelphij scsi_u64to8b(lba, scsi_cmd->addr); 2076242497Sdelphij scsi_cmd->reserved = 0; 2077242497Sdelphij scsi_ulto4b(block_count, scsi_cmd->length); 2078242497Sdelphij scsi_cmd->control = 0; 2079242497Sdelphij cdb_len = sizeof(*scsi_cmd); 2080242497Sdelphij } 2081242497Sdelphij 2082242497Sdelphij return cdb_len; 2083242497Sdelphij} 2084242497Sdelphij 2085233711Sambriskostatic struct mfi_command * 2086233711Sambriskomfi_build_syspdio(struct mfi_softc *sc, struct bio *bio) 2087233711Sambrisko{ 2088233711Sambrisko struct mfi_command *cm; 2089233711Sambrisko struct mfi_pass_frame *pass; 2090242681Sambrisko uint32_t context = 0; 2091242681Sambrisko int flags = 0, blkcount = 0, readop; 2092242497Sdelphij uint8_t cdb_len; 2093157114Sscottl 2094233711Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 2095233711Sambrisko return (NULL); 2096233711Sambrisko 2097233711Sambrisko /* Zero out the MFI frame */ 2098242681Sambrisko context = cm->cm_frame->header.context; 2099233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2100233711Sambrisko cm->cm_frame->header.context = context; 2101233711Sambrisko pass = &cm->cm_frame->pass; 2102233711Sambrisko bzero(pass->cdb, 16); 2103233711Sambrisko pass->header.cmd = MFI_CMD_PD_SCSI_IO; 2104233711Sambrisko switch (bio->bio_cmd & 0x03) { 2105233711Sambrisko case BIO_READ: 2106233711Sambrisko flags = MFI_CMD_DATAIN; 2107242681Sambrisko readop = 1; 2108233711Sambrisko break; 2109233711Sambrisko case BIO_WRITE: 2110233711Sambrisko flags = MFI_CMD_DATAOUT; 2111242681Sambrisko readop = 0; 2112233711Sambrisko break; 2113233711Sambrisko default: 2114242497Sdelphij /* TODO: what about BIO_DELETE??? */ 2115242681Sambrisko panic("Unsupported bio command %x\n", bio->bio_cmd); 2116233711Sambrisko } 2117233711Sambrisko 2118233711Sambrisko /* Cheat with the sector length to avoid a non-constant division */ 2119242681Sambrisko blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2120233711Sambrisko /* Fill the LBA and Transfer length in CDB */ 2121242681Sambrisko cdb_len = mfi_build_cdb(readop, 0, bio->bio_pblkno, blkcount, 2122242681Sambrisko pass->cdb); 2123233711Sambrisko pass->header.target_id = (uintptr_t)bio->bio_driver1; 2124242681Sambrisko pass->header.lun_id = 0; 2125233711Sambrisko pass->header.timeout = 0; 2126233711Sambrisko pass->header.flags = 0; 2127233711Sambrisko pass->header.scsi_status = 0; 2128233711Sambrisko pass->header.sense_len = MFI_SENSE_LEN; 2129233711Sambrisko pass->header.data_len = bio->bio_bcount; 2130242497Sdelphij pass->header.cdb_len = cdb_len; 2131233711Sambrisko pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2132233711Sambrisko pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2133233711Sambrisko cm->cm_complete = mfi_bio_complete; 2134233711Sambrisko cm->cm_private = bio; 2135233711Sambrisko cm->cm_data = bio->bio_data; 2136233711Sambrisko cm->cm_len = bio->bio_bcount; 2137233711Sambrisko cm->cm_sg = &pass->sgl; 2138233711Sambrisko cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; 2139233711Sambrisko cm->cm_flags = flags; 2140233711Sambrisko return (cm); 2141233711Sambrisko} 2142233711Sambrisko 2143233711Sambriskostatic struct mfi_command * 2144233711Sambriskomfi_build_ldio(struct mfi_softc *sc, struct bio *bio) 2145233711Sambrisko{ 2146233711Sambrisko struct mfi_io_frame *io; 2147233711Sambrisko struct mfi_command *cm; 2148242497Sdelphij int flags; 2149242497Sdelphij uint32_t blkcount; 2150233711Sambrisko uint32_t context = 0; 2151233711Sambrisko 2152233711Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 2153233711Sambrisko return (NULL); 2154233711Sambrisko 2155233711Sambrisko /* Zero out the MFI frame */ 2156233711Sambrisko context = cm->cm_frame->header.context; 2157233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2158233711Sambrisko cm->cm_frame->header.context = context; 2159157114Sscottl io = &cm->cm_frame->io; 2160157114Sscottl switch (bio->bio_cmd & 0x03) { 2161157114Sscottl case BIO_READ: 2162157114Sscottl io->header.cmd = MFI_CMD_LD_READ; 2163157114Sscottl flags = MFI_CMD_DATAIN; 2164157114Sscottl break; 2165157114Sscottl case BIO_WRITE: 2166157114Sscottl io->header.cmd = MFI_CMD_LD_WRITE; 2167157114Sscottl flags = MFI_CMD_DATAOUT; 2168157114Sscottl break; 2169157114Sscottl default: 2170242497Sdelphij /* TODO: what about BIO_DELETE??? */ 2171242681Sambrisko panic("Unsupported bio command %x\n", bio->bio_cmd); 2172157114Sscottl } 2173157114Sscottl 2174157114Sscottl /* Cheat with the sector length to avoid a non-constant division */ 2175157114Sscottl blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2176157114Sscottl io->header.target_id = (uintptr_t)bio->bio_driver1; 2177157114Sscottl io->header.timeout = 0; 2178157114Sscottl io->header.flags = 0; 2179233711Sambrisko io->header.scsi_status = 0; 2180157114Sscottl io->header.sense_len = MFI_SENSE_LEN; 2181157114Sscottl io->header.data_len = blkcount; 2182233711Sambrisko io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2183233711Sambrisko io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2184157114Sscottl io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32; 2185157114Sscottl io->lba_lo = bio->bio_pblkno & 0xffffffff; 2186157114Sscottl cm->cm_complete = mfi_bio_complete; 2187157114Sscottl cm->cm_private = bio; 2188157114Sscottl cm->cm_data = bio->bio_data; 2189157114Sscottl cm->cm_len = bio->bio_bcount; 2190157114Sscottl cm->cm_sg = &io->sgl; 2191157114Sscottl cm->cm_total_frame_size = MFI_IO_FRAME_SIZE; 2192157114Sscottl cm->cm_flags = flags; 2193157114Sscottl return (cm); 2194157114Sscottl} 2195157114Sscottl 2196157114Sscottlstatic void 2197157114Sscottlmfi_bio_complete(struct mfi_command *cm) 2198157114Sscottl{ 2199157114Sscottl struct bio *bio; 2200157114Sscottl struct mfi_frame_header *hdr; 2201157114Sscottl struct mfi_softc *sc; 2202157114Sscottl 2203157114Sscottl bio = cm->cm_private; 2204157114Sscottl hdr = &cm->cm_frame->header; 2205157114Sscottl sc = cm->cm_sc; 2206157114Sscottl 2207224039Sjhb if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) { 2208157114Sscottl bio->bio_flags |= BIO_ERROR; 2209157114Sscottl bio->bio_error = EIO; 2210157114Sscottl device_printf(sc->mfi_dev, "I/O error, status= %d " 2211157114Sscottl "scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status); 2212157114Sscottl mfi_print_sense(cm->cm_sc, cm->cm_sense); 2213184897Sambrisko } else if (cm->cm_error != 0) { 2214184897Sambrisko bio->bio_flags |= BIO_ERROR; 2215157114Sscottl } 2216157114Sscottl 2217157114Sscottl mfi_release_command(cm); 2218157114Sscottl mfi_disk_complete(bio); 2219157114Sscottl} 2220157114Sscottl 2221157114Sscottlvoid 2222157114Sscottlmfi_startio(struct mfi_softc *sc) 2223157114Sscottl{ 2224157114Sscottl struct mfi_command *cm; 2225169611Sscottl struct ccb_hdr *ccbh; 2226157114Sscottl 2227157114Sscottl for (;;) { 2228157114Sscottl /* Don't bother if we're short on resources */ 2229157114Sscottl if (sc->mfi_flags & MFI_FLAGS_QFRZN) 2230157114Sscottl break; 2231157114Sscottl 2232157114Sscottl /* Try a command that has already been prepared */ 2233157114Sscottl cm = mfi_dequeue_ready(sc); 2234157114Sscottl 2235169611Sscottl if (cm == NULL) { 2236169611Sscottl if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL) 2237169611Sscottl cm = sc->mfi_cam_start(ccbh); 2238169611Sscottl } 2239169611Sscottl 2240157114Sscottl /* Nope, so look for work on the bioq */ 2241157114Sscottl if (cm == NULL) 2242157114Sscottl cm = mfi_bio_command(sc); 2243157114Sscottl 2244157114Sscottl /* No work available, so exit */ 2245157114Sscottl if (cm == NULL) 2246157114Sscottl break; 2247157114Sscottl 2248157114Sscottl /* Send the command to the controller */ 2249157114Sscottl if (mfi_mapcmd(sc, cm) != 0) { 2250157114Sscottl mfi_requeue_ready(cm); 2251157114Sscottl break; 2252157114Sscottl } 2253157114Sscottl } 2254157114Sscottl} 2255157114Sscottl 2256233711Sambriskoint 2257157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm) 2258157114Sscottl{ 2259157114Sscottl int error, polled; 2260157114Sscottl 2261163398Sscottl mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2262163398Sscottl 2263233711Sambrisko if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) { 2264157114Sscottl polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0; 2265157114Sscottl error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap, 2266157114Sscottl cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled); 2267157114Sscottl if (error == EINPROGRESS) { 2268157114Sscottl sc->mfi_flags |= MFI_FLAGS_QFRZN; 2269157114Sscottl return (0); 2270157114Sscottl } 2271157114Sscottl } else { 2272233711Sambrisko if (sc->MFA_enabled) 2273233711Sambrisko error = mfi_tbolt_send_frame(sc, cm); 2274233711Sambrisko else 2275233711Sambrisko error = mfi_send_frame(sc, cm); 2276157114Sscottl } 2277157114Sscottl 2278157114Sscottl return (error); 2279157114Sscottl} 2280157114Sscottl 2281157114Sscottlstatic void 2282157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 2283157114Sscottl{ 2284157114Sscottl struct mfi_frame_header *hdr; 2285157114Sscottl struct mfi_command *cm; 2286157237Sscottl union mfi_sgl *sgl; 2287157114Sscottl struct mfi_softc *sc; 2288225869Smav int i, j, first, dir; 2289233711Sambrisko int sge_size; 2290157114Sscottl 2291157114Sscottl cm = (struct mfi_command *)arg; 2292157114Sscottl sc = cm->cm_sc; 2293157237Sscottl hdr = &cm->cm_frame->header; 2294157237Sscottl sgl = cm->cm_sg; 2295157114Sscottl 2296170284Sambrisko if (error) { 2297170284Sambrisko printf("error %d in callback\n", error); 2298170284Sambrisko cm->cm_error = error; 2299170284Sambrisko mfi_complete(sc, cm); 2300170284Sambrisko return; 2301170284Sambrisko } 2302233711Sambrisko /* Use IEEE sgl only for IO's on a SKINNY controller 2303233711Sambrisko * For other commands on a SKINNY controller use either 2304233711Sambrisko * sg32 or sg64 based on the sizeof(bus_addr_t). 2305233711Sambrisko * Also calculate the total frame size based on the type 2306233711Sambrisko * of SGL used. 2307233711Sambrisko */ 2308233711Sambrisko if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) || 2309233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) || 2310233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) && 2311233711Sambrisko (sc->mfi_flags & MFI_FLAGS_SKINNY)) { 2312157237Sscottl for (i = 0; i < nsegs; i++) { 2313233711Sambrisko sgl->sg_skinny[i].addr = segs[i].ds_addr; 2314233711Sambrisko sgl->sg_skinny[i].len = segs[i].ds_len; 2315233711Sambrisko sgl->sg_skinny[i].flag = 0; 2316157114Sscottl } 2317233711Sambrisko hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64; 2318233711Sambrisko sge_size = sizeof(struct mfi_sg_skinny); 2319233711Sambrisko hdr->sg_count = nsegs; 2320157237Sscottl } else { 2321233711Sambrisko j = 0; 2322233711Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 2323233711Sambrisko first = cm->cm_stp_len; 2324233711Sambrisko if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { 2325233711Sambrisko sgl->sg32[j].addr = segs[0].ds_addr; 2326233711Sambrisko sgl->sg32[j++].len = first; 2327233711Sambrisko } else { 2328233711Sambrisko sgl->sg64[j].addr = segs[0].ds_addr; 2329233711Sambrisko sgl->sg64[j++].len = first; 2330233711Sambrisko } 2331233711Sambrisko } else 2332225869Smav first = 0; 2333233711Sambrisko if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { 2334233711Sambrisko for (i = 0; i < nsegs; i++) { 2335233711Sambrisko sgl->sg32[j].addr = segs[i].ds_addr + first; 2336233711Sambrisko sgl->sg32[j++].len = segs[i].ds_len - first; 2337233711Sambrisko first = 0; 2338233711Sambrisko } 2339233711Sambrisko } else { 2340233711Sambrisko for (i = 0; i < nsegs; i++) { 2341233711Sambrisko sgl->sg64[j].addr = segs[i].ds_addr + first; 2342233711Sambrisko sgl->sg64[j++].len = segs[i].ds_len - first; 2343233711Sambrisko first = 0; 2344233711Sambrisko } 2345233711Sambrisko hdr->flags |= MFI_FRAME_SGL64; 2346157237Sscottl } 2347233711Sambrisko hdr->sg_count = j; 2348233711Sambrisko sge_size = sc->mfi_sge_size; 2349157114Sscottl } 2350157114Sscottl 2351157114Sscottl dir = 0; 2352157114Sscottl if (cm->cm_flags & MFI_CMD_DATAIN) { 2353157114Sscottl dir |= BUS_DMASYNC_PREREAD; 2354157114Sscottl hdr->flags |= MFI_FRAME_DIR_READ; 2355157114Sscottl } 2356157114Sscottl if (cm->cm_flags & MFI_CMD_DATAOUT) { 2357157114Sscottl dir |= BUS_DMASYNC_PREWRITE; 2358157114Sscottl hdr->flags |= MFI_FRAME_DIR_WRITE; 2359157114Sscottl } 2360157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir); 2361157114Sscottl cm->cm_flags |= MFI_CMD_MAPPED; 2362157114Sscottl 2363157114Sscottl /* 2364157114Sscottl * Instead of calculating the total number of frames in the 2365157114Sscottl * compound frame, it's already assumed that there will be at 2366157114Sscottl * least 1 frame, so don't compensate for the modulo of the 2367157114Sscottl * following division. 2368157114Sscottl */ 2369162458Sscottl cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs); 2370157114Sscottl cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; 2371157114Sscottl 2372233711Sambrisko if (sc->MFA_enabled) 2373233711Sambrisko mfi_tbolt_send_frame(sc, cm); 2374233711Sambrisko else 2375233711Sambrisko mfi_send_frame(sc, cm); 2376157114Sscottl 2377157114Sscottl return; 2378157114Sscottl} 2379157114Sscottl 2380157114Sscottlstatic int 2381157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm) 2382157114Sscottl{ 2383164375Sscottl struct mfi_frame_header *hdr; 2384165225Sambrisko int tm = MFI_POLL_TIMEOUT_SECS * 1000; 2385157114Sscottl 2386164375Sscottl hdr = &cm->cm_frame->header; 2387164375Sscottl 2388164375Sscottl if ((cm->cm_flags & MFI_CMD_POLLED) == 0) { 2389164375Sscottl cm->cm_timestamp = time_uptime; 2390164375Sscottl mfi_enqueue_busy(cm); 2391164375Sscottl } else { 2392224039Sjhb hdr->cmd_status = MFI_STAT_INVALID_STATUS; 2393164375Sscottl hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 2394164375Sscottl } 2395164375Sscottl 2396157114Sscottl /* 2397157114Sscottl * The bus address of the command is aligned on a 64 byte boundary, 2398157114Sscottl * leaving the least 6 bits as zero. For whatever reason, the 2399157114Sscottl * hardware wants the address shifted right by three, leaving just 2400162458Sscottl * 3 zero bits. These three bits are then used as a prefetching 2401162458Sscottl * hint for the hardware to predict how many frames need to be 2402162458Sscottl * fetched across the bus. If a command has more than 8 frames 2403162458Sscottl * then the 3 bits are set to 0x7 and the firmware uses other 2404162458Sscottl * information in the command to determine the total amount to fetch. 2405162458Sscottl * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames 2406162458Sscottl * is enough for both 32bit and 64bit systems. 2407157114Sscottl */ 2408162458Sscottl if (cm->cm_extra_frames > 7) 2409162458Sscottl cm->cm_extra_frames = 7; 2410162458Sscottl 2411233711Sambrisko sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames); 2412164375Sscottl 2413164375Sscottl if ((cm->cm_flags & MFI_CMD_POLLED) == 0) 2414164375Sscottl return (0); 2415164375Sscottl 2416164375Sscottl /* This is a polled command, so busy-wait for it to complete. */ 2417224039Sjhb while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 2418164375Sscottl DELAY(1000); 2419165225Sambrisko tm -= 1; 2420164375Sscottl if (tm <= 0) 2421164375Sscottl break; 2422164375Sscottl } 2423164375Sscottl 2424224039Sjhb if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 2425165225Sambrisko device_printf(sc->mfi_dev, "Frame %p timed out " 2426233711Sambrisko "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode); 2427164375Sscottl return (ETIMEDOUT); 2428164375Sscottl } 2429164375Sscottl 2430157114Sscottl return (0); 2431157114Sscottl} 2432157114Sscottl 2433233711Sambrisko 2434233711Sambriskovoid 2435157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm) 2436157114Sscottl{ 2437157114Sscottl int dir; 2438157114Sscottl 2439157114Sscottl if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) { 2440157114Sscottl dir = 0; 2441225869Smav if ((cm->cm_flags & MFI_CMD_DATAIN) || 2442225869Smav (cm->cm_frame->header.cmd == MFI_CMD_STP)) 2443157114Sscottl dir |= BUS_DMASYNC_POSTREAD; 2444157114Sscottl if (cm->cm_flags & MFI_CMD_DATAOUT) 2445157114Sscottl dir |= BUS_DMASYNC_POSTWRITE; 2446157114Sscottl 2447157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir); 2448157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2449157114Sscottl cm->cm_flags &= ~MFI_CMD_MAPPED; 2450157114Sscottl } 2451157114Sscottl 2452170284Sambrisko cm->cm_flags |= MFI_CMD_COMPLETED; 2453170284Sambrisko 2454157114Sscottl if (cm->cm_complete != NULL) 2455157114Sscottl cm->cm_complete(cm); 2456159811Sps else 2457159811Sps wakeup(cm); 2458157114Sscottl} 2459157114Sscottl 2460158737Sambriskostatic int 2461242681Sambriskomfi_abort(struct mfi_softc *sc, struct mfi_command **cm_abort) 2462158737Sambrisko{ 2463158737Sambrisko struct mfi_command *cm; 2464158737Sambrisko struct mfi_abort_frame *abort; 2465165225Sambrisko int i = 0; 2466233711Sambrisko uint32_t context = 0; 2467158737Sambrisko 2468242681Sambrisko mtx_lock(&sc->mfi_io_lock); 2469158737Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 2470158737Sambrisko return (EBUSY); 2471158737Sambrisko } 2472158737Sambrisko 2473233711Sambrisko /* Zero out the MFI frame */ 2474233711Sambrisko context = cm->cm_frame->header.context; 2475233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2476233711Sambrisko cm->cm_frame->header.context = context; 2477233711Sambrisko 2478158737Sambrisko abort = &cm->cm_frame->abort; 2479158737Sambrisko abort->header.cmd = MFI_CMD_ABORT; 2480158737Sambrisko abort->header.flags = 0; 2481233711Sambrisko abort->header.scsi_status = 0; 2482242681Sambrisko abort->abort_context = (*cm_abort)->cm_frame->header.context; 2483242681Sambrisko abort->abort_mfi_addr_lo = (uint32_t)(*cm_abort)->cm_frame_busaddr; 2484233711Sambrisko abort->abort_mfi_addr_hi = 2485242681Sambrisko (uint32_t)((uint64_t)(*cm_abort)->cm_frame_busaddr >> 32); 2486158737Sambrisko cm->cm_data = NULL; 2487164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 2488158737Sambrisko 2489158737Sambrisko mfi_mapcmd(sc, cm); 2490158737Sambrisko mfi_release_command(cm); 2491158737Sambrisko 2492242681Sambrisko mtx_unlock(&sc->mfi_io_lock); 2493242681Sambrisko while (i < 5 && *cm_abort != NULL) { 2494242681Sambrisko tsleep(cm_abort, 0, "mfiabort", 2495233711Sambrisko 5 * hz); 2496165225Sambrisko i++; 2497158737Sambrisko } 2498242681Sambrisko if (*cm_abort != NULL) { 2499242681Sambrisko /* Force a complete if command didn't abort */ 2500242681Sambrisko mtx_lock(&sc->mfi_io_lock); 2501242681Sambrisko (*cm_abort)->cm_complete(*cm_abort); 2502242681Sambrisko mtx_unlock(&sc->mfi_io_lock); 2503235014Sambrisko } 2504158737Sambrisko 2505158737Sambrisko return (0); 2506158737Sambrisko} 2507158737Sambrisko 2508157114Sscottlint 2509233711Sambriskomfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, 2510233711Sambrisko int len) 2511157114Sscottl{ 2512157114Sscottl struct mfi_command *cm; 2513157114Sscottl struct mfi_io_frame *io; 2514157114Sscottl int error; 2515233711Sambrisko uint32_t context = 0; 2516157114Sscottl 2517157114Sscottl if ((cm = mfi_dequeue_free(sc)) == NULL) 2518157114Sscottl return (EBUSY); 2519157114Sscottl 2520233711Sambrisko /* Zero out the MFI frame */ 2521233711Sambrisko context = cm->cm_frame->header.context; 2522233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2523233711Sambrisko cm->cm_frame->header.context = context; 2524233711Sambrisko 2525157114Sscottl io = &cm->cm_frame->io; 2526157114Sscottl io->header.cmd = MFI_CMD_LD_WRITE; 2527157114Sscottl io->header.target_id = id; 2528157114Sscottl io->header.timeout = 0; 2529157114Sscottl io->header.flags = 0; 2530233711Sambrisko io->header.scsi_status = 0; 2531157114Sscottl io->header.sense_len = MFI_SENSE_LEN; 2532157114Sscottl io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2533233711Sambrisko io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2534233711Sambrisko io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2535157114Sscottl io->lba_hi = (lba & 0xffffffff00000000) >> 32; 2536157114Sscottl io->lba_lo = lba & 0xffffffff; 2537157114Sscottl cm->cm_data = virt; 2538157114Sscottl cm->cm_len = len; 2539157114Sscottl cm->cm_sg = &io->sgl; 2540157114Sscottl cm->cm_total_frame_size = MFI_IO_FRAME_SIZE; 2541157114Sscottl cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT; 2542157114Sscottl 2543164375Sscottl error = mfi_mapcmd(sc, cm); 2544157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 2545157114Sscottl BUS_DMASYNC_POSTWRITE); 2546157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2547157114Sscottl mfi_release_command(cm); 2548157114Sscottl 2549157114Sscottl return (error); 2550157114Sscottl} 2551157114Sscottl 2552233711Sambriskoint 2553233711Sambriskomfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, 2554233711Sambrisko int len) 2555233711Sambrisko{ 2556233711Sambrisko struct mfi_command *cm; 2557233711Sambrisko struct mfi_pass_frame *pass; 2558242681Sambrisko int error, readop, cdb_len; 2559242497Sdelphij uint32_t blkcount; 2560233711Sambrisko 2561233711Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 2562233711Sambrisko return (EBUSY); 2563233711Sambrisko 2564233711Sambrisko pass = &cm->cm_frame->pass; 2565233711Sambrisko bzero(pass->cdb, 16); 2566233711Sambrisko pass->header.cmd = MFI_CMD_PD_SCSI_IO; 2567242681Sambrisko 2568242681Sambrisko readop = 0; 2569233711Sambrisko blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2570242681Sambrisko cdb_len = mfi_build_cdb(readop, 0, lba, blkcount, pass->cdb); 2571233711Sambrisko pass->header.target_id = id; 2572233711Sambrisko pass->header.timeout = 0; 2573233711Sambrisko pass->header.flags = 0; 2574233711Sambrisko pass->header.scsi_status = 0; 2575233711Sambrisko pass->header.sense_len = MFI_SENSE_LEN; 2576233711Sambrisko pass->header.data_len = len; 2577242681Sambrisko pass->header.cdb_len = cdb_len; 2578233711Sambrisko pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2579233711Sambrisko pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2580233711Sambrisko cm->cm_data = virt; 2581233711Sambrisko cm->cm_len = len; 2582233711Sambrisko cm->cm_sg = &pass->sgl; 2583233711Sambrisko cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; 2584242681Sambrisko cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT | MFI_CMD_SCSI; 2585233711Sambrisko 2586233711Sambrisko error = mfi_mapcmd(sc, cm); 2587233711Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 2588233711Sambrisko BUS_DMASYNC_POSTWRITE); 2589233711Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2590233711Sambrisko mfi_release_command(cm); 2591233711Sambrisko 2592233711Sambrisko return (error); 2593233711Sambrisko} 2594233711Sambrisko 2595157114Sscottlstatic int 2596192450Simpmfi_open(struct cdev *dev, int flags, int fmt, struct thread *td) 2597157114Sscottl{ 2598157114Sscottl struct mfi_softc *sc; 2599171822Sjhb int error; 2600157114Sscottl 2601157114Sscottl sc = dev->si_drv1; 2602163398Sscottl 2603163398Sscottl mtx_lock(&sc->mfi_io_lock); 2604171822Sjhb if (sc->mfi_detaching) 2605171822Sjhb error = ENXIO; 2606171822Sjhb else { 2607171822Sjhb sc->mfi_flags |= MFI_FLAGS_OPEN; 2608171822Sjhb error = 0; 2609171822Sjhb } 2610163398Sscottl mtx_unlock(&sc->mfi_io_lock); 2611157114Sscottl 2612171822Sjhb return (error); 2613157114Sscottl} 2614157114Sscottl 2615157114Sscottlstatic int 2616192450Simpmfi_close(struct cdev *dev, int flags, int fmt, struct thread *td) 2617157114Sscottl{ 2618157114Sscottl struct mfi_softc *sc; 2619163398Sscottl struct mfi_aen *mfi_aen_entry, *tmp; 2620157114Sscottl 2621157114Sscottl sc = dev->si_drv1; 2622163398Sscottl 2623163398Sscottl mtx_lock(&sc->mfi_io_lock); 2624157114Sscottl sc->mfi_flags &= ~MFI_FLAGS_OPEN; 2625157114Sscottl 2626163398Sscottl TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) { 2627158737Sambrisko if (mfi_aen_entry->p == curproc) { 2628158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 2629158737Sambrisko aen_link); 2630158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 2631158737Sambrisko } 2632158737Sambrisko } 2633163398Sscottl mtx_unlock(&sc->mfi_io_lock); 2634157114Sscottl return (0); 2635157114Sscottl} 2636157114Sscottl 2637157114Sscottlstatic int 2638171821Sjhbmfi_config_lock(struct mfi_softc *sc, uint32_t opcode) 2639171821Sjhb{ 2640171821Sjhb 2641171821Sjhb switch (opcode) { 2642171821Sjhb case MFI_DCMD_LD_DELETE: 2643171821Sjhb case MFI_DCMD_CFG_ADD: 2644171821Sjhb case MFI_DCMD_CFG_CLEAR: 2645240962Sjhb case MFI_DCMD_CFG_FOREIGN_IMPORT: 2646171821Sjhb sx_xlock(&sc->mfi_config_lock); 2647171821Sjhb return (1); 2648171821Sjhb default: 2649171821Sjhb return (0); 2650171821Sjhb } 2651171821Sjhb} 2652171821Sjhb 2653171821Sjhbstatic void 2654171821Sjhbmfi_config_unlock(struct mfi_softc *sc, int locked) 2655171821Sjhb{ 2656171821Sjhb 2657171821Sjhb if (locked) 2658171821Sjhb sx_xunlock(&sc->mfi_config_lock); 2659171821Sjhb} 2660171821Sjhb 2661233711Sambrisko/* 2662233711Sambrisko * Perform pre-issue checks on commands from userland and possibly veto 2663233711Sambrisko * them. 2664233711Sambrisko */ 2665171821Sjhbstatic int 2666171821Sjhbmfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm) 2667171821Sjhb{ 2668171821Sjhb struct mfi_disk *ld, *ld2; 2669171821Sjhb int error; 2670233711Sambrisko struct mfi_system_pd *syspd = NULL; 2671233711Sambrisko uint16_t syspd_id; 2672233711Sambrisko uint16_t *mbox; 2673171821Sjhb 2674171821Sjhb mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2675171821Sjhb error = 0; 2676171821Sjhb switch (cm->cm_frame->dcmd.opcode) { 2677171821Sjhb case MFI_DCMD_LD_DELETE: 2678171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2679171821Sjhb if (ld->ld_id == cm->cm_frame->dcmd.mbox[0]) 2680171821Sjhb break; 2681171821Sjhb } 2682171821Sjhb if (ld == NULL) 2683171821Sjhb error = ENOENT; 2684171821Sjhb else 2685171821Sjhb error = mfi_disk_disable(ld); 2686171821Sjhb break; 2687171821Sjhb case MFI_DCMD_CFG_CLEAR: 2688171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2689171821Sjhb error = mfi_disk_disable(ld); 2690171821Sjhb if (error) 2691171821Sjhb break; 2692171821Sjhb } 2693171821Sjhb if (error) { 2694171821Sjhb TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) { 2695171821Sjhb if (ld2 == ld) 2696171821Sjhb break; 2697171821Sjhb mfi_disk_enable(ld2); 2698171821Sjhb } 2699171821Sjhb } 2700171821Sjhb break; 2701233711Sambrisko case MFI_DCMD_PD_STATE_SET: 2702233711Sambrisko mbox = (uint16_t *) cm->cm_frame->dcmd.mbox; 2703233711Sambrisko syspd_id = mbox[0]; 2704233711Sambrisko if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { 2705233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { 2706233711Sambrisko if (syspd->pd_id == syspd_id) 2707233711Sambrisko break; 2708233711Sambrisko } 2709233711Sambrisko } 2710233711Sambrisko else 2711233711Sambrisko break; 2712233711Sambrisko if (syspd) 2713233711Sambrisko error = mfi_syspd_disable(syspd); 2714233711Sambrisko break; 2715171821Sjhb default: 2716171821Sjhb break; 2717171821Sjhb } 2718171821Sjhb return (error); 2719171821Sjhb} 2720171821Sjhb 2721171821Sjhb/* Perform post-issue checks on commands from userland. */ 2722171821Sjhbstatic void 2723171821Sjhbmfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm) 2724171821Sjhb{ 2725171821Sjhb struct mfi_disk *ld, *ldn; 2726233711Sambrisko struct mfi_system_pd *syspd = NULL; 2727233711Sambrisko uint16_t syspd_id; 2728233711Sambrisko uint16_t *mbox; 2729171821Sjhb 2730171821Sjhb switch (cm->cm_frame->dcmd.opcode) { 2731171821Sjhb case MFI_DCMD_LD_DELETE: 2732171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2733171821Sjhb if (ld->ld_id == cm->cm_frame->dcmd.mbox[0]) 2734171821Sjhb break; 2735171821Sjhb } 2736171821Sjhb KASSERT(ld != NULL, ("volume dissappeared")); 2737171821Sjhb if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { 2738171821Sjhb mtx_unlock(&sc->mfi_io_lock); 2739196403Sjhb mtx_lock(&Giant); 2740171821Sjhb device_delete_child(sc->mfi_dev, ld->ld_dev); 2741196403Sjhb mtx_unlock(&Giant); 2742171821Sjhb mtx_lock(&sc->mfi_io_lock); 2743171821Sjhb } else 2744171821Sjhb mfi_disk_enable(ld); 2745171821Sjhb break; 2746171821Sjhb case MFI_DCMD_CFG_CLEAR: 2747171821Sjhb if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { 2748171821Sjhb mtx_unlock(&sc->mfi_io_lock); 2749196403Sjhb mtx_lock(&Giant); 2750171821Sjhb TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) { 2751171821Sjhb device_delete_child(sc->mfi_dev, ld->ld_dev); 2752171821Sjhb } 2753196403Sjhb mtx_unlock(&Giant); 2754171821Sjhb mtx_lock(&sc->mfi_io_lock); 2755171821Sjhb } else { 2756171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) 2757171821Sjhb mfi_disk_enable(ld); 2758171821Sjhb } 2759171821Sjhb break; 2760171821Sjhb case MFI_DCMD_CFG_ADD: 2761171821Sjhb mfi_ldprobe(sc); 2762171821Sjhb break; 2763184897Sambrisko case MFI_DCMD_CFG_FOREIGN_IMPORT: 2764184897Sambrisko mfi_ldprobe(sc); 2765184897Sambrisko break; 2766233711Sambrisko case MFI_DCMD_PD_STATE_SET: 2767233711Sambrisko mbox = (uint16_t *) cm->cm_frame->dcmd.mbox; 2768233711Sambrisko syspd_id = mbox[0]; 2769233711Sambrisko if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { 2770233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) { 2771233711Sambrisko if (syspd->pd_id == syspd_id) 2772233711Sambrisko break; 2773233711Sambrisko } 2774233711Sambrisko } 2775233711Sambrisko else 2776233711Sambrisko break; 2777233711Sambrisko /* If the transition fails then enable the syspd again */ 2778233711Sambrisko if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK) 2779233711Sambrisko mfi_syspd_enable(syspd); 2780233711Sambrisko break; 2781171821Sjhb } 2782171821Sjhb} 2783171821Sjhb 2784242681Sambriskostatic int 2785242681Sambriskomfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm) 2786233711Sambrisko{ 2787242681Sambrisko struct mfi_config_data *conf_data; 2788233711Sambrisko struct mfi_command *ld_cm = NULL; 2789233711Sambrisko struct mfi_ld_info *ld_info = NULL; 2790242681Sambrisko struct mfi_ld_config *ld; 2791242681Sambrisko char *p; 2792233711Sambrisko int error = 0; 2793233711Sambrisko 2794242681Sambrisko conf_data = (struct mfi_config_data *)cm->cm_data; 2795242681Sambrisko 2796242681Sambrisko if (cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) { 2797242681Sambrisko p = (char *)conf_data->array; 2798242681Sambrisko p += conf_data->array_size * conf_data->array_count; 2799242681Sambrisko ld = (struct mfi_ld_config *)p; 2800242681Sambrisko if (ld->params.isSSCD == 1) 2801242681Sambrisko error = 1; 2802233711Sambrisko } else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) { 2803233711Sambrisko error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO, 2804233711Sambrisko (void **)&ld_info, sizeof(*ld_info)); 2805235016Sambrisko if (error) { 2806233711Sambrisko device_printf(sc->mfi_dev, "Failed to allocate" 2807233711Sambrisko "MFI_DCMD_LD_GET_INFO %d", error); 2808233711Sambrisko if (ld_info) 2809233711Sambrisko free(ld_info, M_MFIBUF); 2810233711Sambrisko return 0; 2811233711Sambrisko } 2812233711Sambrisko ld_cm->cm_flags = MFI_CMD_DATAIN; 2813233711Sambrisko ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0]; 2814233711Sambrisko ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0]; 2815235016Sambrisko if (mfi_wait_command(sc, ld_cm) != 0) { 2816233711Sambrisko device_printf(sc->mfi_dev, "failed to get log drv\n"); 2817233711Sambrisko mfi_release_command(ld_cm); 2818233711Sambrisko free(ld_info, M_MFIBUF); 2819233711Sambrisko return 0; 2820233711Sambrisko } 2821233711Sambrisko 2822233711Sambrisko if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) { 2823233711Sambrisko free(ld_info, M_MFIBUF); 2824233711Sambrisko mfi_release_command(ld_cm); 2825233711Sambrisko return 0; 2826233711Sambrisko } 2827233711Sambrisko else 2828233711Sambrisko ld_info = (struct mfi_ld_info *)ld_cm->cm_private; 2829233711Sambrisko 2830233711Sambrisko if (ld_info->ld_config.params.isSSCD == 1) 2831233711Sambrisko error = 1; 2832233711Sambrisko 2833233711Sambrisko mfi_release_command(ld_cm); 2834233711Sambrisko free(ld_info, M_MFIBUF); 2835233711Sambrisko 2836233711Sambrisko } 2837233711Sambrisko return error; 2838233711Sambrisko} 2839233711Sambrisko 2840171821Sjhbstatic int 2841233711Sambriskomfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg) 2842233711Sambrisko{ 2843233711Sambrisko uint8_t i; 2844233711Sambrisko struct mfi_ioc_packet *ioc; 2845233711Sambrisko ioc = (struct mfi_ioc_packet *)arg; 2846233711Sambrisko int sge_size, error; 2847233711Sambrisko struct megasas_sge *kern_sge; 2848233711Sambrisko 2849233711Sambrisko memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr)); 2850233711Sambrisko kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off); 2851233711Sambrisko cm->cm_frame->header.sg_count = ioc->mfi_sge_count; 2852233711Sambrisko 2853233711Sambrisko if (sizeof(bus_addr_t) == 8) { 2854233711Sambrisko cm->cm_frame->header.flags |= MFI_FRAME_SGL64; 2855233711Sambrisko cm->cm_extra_frames = 2; 2856233711Sambrisko sge_size = sizeof(struct mfi_sg64); 2857233711Sambrisko } else { 2858233711Sambrisko cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; 2859233711Sambrisko sge_size = sizeof(struct mfi_sg32); 2860233711Sambrisko } 2861233711Sambrisko 2862233711Sambrisko cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count); 2863233711Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 2864233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 2865233711Sambrisko 1, 0, /* algnmnt, boundary */ 2866233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 2867233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 2868233711Sambrisko NULL, NULL, /* filter, filterarg */ 2869233711Sambrisko ioc->mfi_sgl[i].iov_len,/* maxsize */ 2870233711Sambrisko 2, /* nsegments */ 2871233711Sambrisko ioc->mfi_sgl[i].iov_len,/* maxsegsize */ 2872233711Sambrisko BUS_DMA_ALLOCNOW, /* flags */ 2873233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 2874233711Sambrisko &sc->mfi_kbuff_arr_dmat[i])) { 2875233711Sambrisko device_printf(sc->mfi_dev, 2876233711Sambrisko "Cannot allocate mfi_kbuff_arr_dmat tag\n"); 2877233711Sambrisko return (ENOMEM); 2878233711Sambrisko } 2879233711Sambrisko 2880233711Sambrisko if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i], 2881233711Sambrisko (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT, 2882233711Sambrisko &sc->mfi_kbuff_arr_dmamap[i])) { 2883233711Sambrisko device_printf(sc->mfi_dev, 2884233711Sambrisko "Cannot allocate mfi_kbuff_arr_dmamap memory\n"); 2885233711Sambrisko return (ENOMEM); 2886233711Sambrisko } 2887233711Sambrisko 2888233711Sambrisko bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i], 2889233711Sambrisko sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i], 2890233711Sambrisko ioc->mfi_sgl[i].iov_len, mfi_addr_cb, 2891233711Sambrisko &sc->mfi_kbuff_arr_busaddr[i], 0); 2892233711Sambrisko 2893233711Sambrisko if (!sc->kbuff_arr[i]) { 2894233711Sambrisko device_printf(sc->mfi_dev, 2895233711Sambrisko "Could not allocate memory for kbuff_arr info\n"); 2896233711Sambrisko return -1; 2897233711Sambrisko } 2898233711Sambrisko kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i]; 2899233711Sambrisko kern_sge[i].length = ioc->mfi_sgl[i].iov_len; 2900233711Sambrisko 2901233711Sambrisko if (sizeof(bus_addr_t) == 8) { 2902233711Sambrisko cm->cm_frame->stp.sgl.sg64[i].addr = 2903233711Sambrisko kern_sge[i].phys_addr; 2904233711Sambrisko cm->cm_frame->stp.sgl.sg64[i].len = 2905233711Sambrisko ioc->mfi_sgl[i].iov_len; 2906233711Sambrisko } else { 2907233711Sambrisko cm->cm_frame->stp.sgl.sg32[i].len = 2908233711Sambrisko kern_sge[i].phys_addr; 2909233711Sambrisko cm->cm_frame->stp.sgl.sg32[i].len = 2910233711Sambrisko ioc->mfi_sgl[i].iov_len; 2911233711Sambrisko } 2912233711Sambrisko 2913233711Sambrisko error = copyin(ioc->mfi_sgl[i].iov_base, 2914233711Sambrisko sc->kbuff_arr[i], 2915233711Sambrisko ioc->mfi_sgl[i].iov_len); 2916233711Sambrisko if (error != 0) { 2917233711Sambrisko device_printf(sc->mfi_dev, "Copy in failed\n"); 2918233711Sambrisko return error; 2919233711Sambrisko } 2920233711Sambrisko } 2921233711Sambrisko 2922233711Sambrisko cm->cm_flags |=MFI_CMD_MAPPED; 2923233711Sambrisko return 0; 2924233711Sambrisko} 2925233711Sambrisko 2926233711Sambriskostatic int 2927178968Sscottlmfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc) 2928178968Sscottl{ 2929178968Sscottl struct mfi_command *cm; 2930178968Sscottl struct mfi_dcmd_frame *dcmd; 2931178968Sscottl void *ioc_buf = NULL; 2932178968Sscottl uint32_t context; 2933178968Sscottl int error = 0, locked; 2934178968Sscottl 2935178968Sscottl 2936178968Sscottl if (ioc->buf_size > 0) { 2937238077Sjhb if (ioc->buf_size > 1024 * 1024) 2938238077Sjhb return (ENOMEM); 2939178968Sscottl ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK); 2940178968Sscottl error = copyin(ioc->buf, ioc_buf, ioc->buf_size); 2941178968Sscottl if (error) { 2942178968Sscottl device_printf(sc->mfi_dev, "failed to copyin\n"); 2943178968Sscottl free(ioc_buf, M_MFIBUF); 2944178968Sscottl return (error); 2945178968Sscottl } 2946178968Sscottl } 2947178968Sscottl 2948178968Sscottl locked = mfi_config_lock(sc, ioc->ioc_frame.opcode); 2949178968Sscottl 2950178968Sscottl mtx_lock(&sc->mfi_io_lock); 2951178968Sscottl while ((cm = mfi_dequeue_free(sc)) == NULL) 2952178968Sscottl msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz); 2953178968Sscottl 2954178968Sscottl /* Save context for later */ 2955178968Sscottl context = cm->cm_frame->header.context; 2956178968Sscottl 2957178968Sscottl dcmd = &cm->cm_frame->dcmd; 2958178968Sscottl bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame)); 2959178968Sscottl 2960178968Sscottl cm->cm_sg = &dcmd->sgl; 2961178968Sscottl cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 2962178968Sscottl cm->cm_data = ioc_buf; 2963178968Sscottl cm->cm_len = ioc->buf_size; 2964178968Sscottl 2965178968Sscottl /* restore context */ 2966178968Sscottl cm->cm_frame->header.context = context; 2967178968Sscottl 2968178968Sscottl /* Cheat since we don't know if we're writing or reading */ 2969178968Sscottl cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT; 2970178968Sscottl 2971178968Sscottl error = mfi_check_command_pre(sc, cm); 2972178968Sscottl if (error) 2973178968Sscottl goto out; 2974178968Sscottl 2975178968Sscottl error = mfi_wait_command(sc, cm); 2976178968Sscottl if (error) { 2977178968Sscottl device_printf(sc->mfi_dev, "ioctl failed %d\n", error); 2978178968Sscottl goto out; 2979178968Sscottl } 2980178968Sscottl bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame)); 2981178968Sscottl mfi_check_command_post(sc, cm); 2982178968Sscottlout: 2983178968Sscottl mfi_release_command(cm); 2984178968Sscottl mtx_unlock(&sc->mfi_io_lock); 2985178968Sscottl mfi_config_unlock(sc, locked); 2986178968Sscottl if (ioc->buf_size > 0) 2987178968Sscottl error = copyout(ioc_buf, ioc->buf, ioc->buf_size); 2988178968Sscottl if (ioc_buf) 2989178968Sscottl free(ioc_buf, M_MFIBUF); 2990178968Sscottl return (error); 2991178968Sscottl} 2992178968Sscottl 2993178968Sscottl#define PTRIN(p) ((void *)(uintptr_t)(p)) 2994178968Sscottl 2995178968Sscottlstatic int 2996192450Simpmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 2997157114Sscottl{ 2998157114Sscottl struct mfi_softc *sc; 2999157114Sscottl union mfi_statrequest *ms; 3000164281Sambrisko struct mfi_ioc_packet *ioc; 3001233711Sambrisko#ifdef COMPAT_FREEBSD32 3002179392Sambrisko struct mfi_ioc_packet32 *ioc32; 3003179392Sambrisko#endif 3004164281Sambrisko struct mfi_ioc_aen *aen; 3005164281Sambrisko struct mfi_command *cm = NULL; 3006233711Sambrisko uint32_t context = 0; 3007184897Sambrisko union mfi_sense_ptr sense_ptr; 3008233711Sambrisko uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0; 3009225869Smav size_t len; 3010233711Sambrisko int i, res; 3011178968Sscottl struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg; 3012233711Sambrisko#ifdef COMPAT_FREEBSD32 3013178968Sscottl struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg; 3014178968Sscottl struct mfi_ioc_passthru iop_swab; 3015178968Sscottl#endif 3016171821Sjhb int error, locked; 3017233711Sambrisko union mfi_sgl *sgl; 3018157114Sscottl sc = dev->si_drv1; 3019157114Sscottl error = 0; 3020157114Sscottl 3021233711Sambrisko if (sc->adpreset) 3022233711Sambrisko return EBUSY; 3023233711Sambrisko 3024233711Sambrisko if (sc->hw_crit_error) 3025233711Sambrisko return EBUSY; 3026233711Sambrisko 3027233711Sambrisko if (sc->issuepend_done == 0) 3028233711Sambrisko return EBUSY; 3029233711Sambrisko 3030157114Sscottl switch (cmd) { 3031157114Sscottl case MFIIO_STATS: 3032157114Sscottl ms = (union mfi_statrequest *)arg; 3033157114Sscottl switch (ms->ms_item) { 3034157114Sscottl case MFIQ_FREE: 3035157114Sscottl case MFIQ_BIO: 3036157114Sscottl case MFIQ_READY: 3037157114Sscottl case MFIQ_BUSY: 3038157114Sscottl bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat, 3039157114Sscottl sizeof(struct mfi_qstat)); 3040157114Sscottl break; 3041157114Sscottl default: 3042158737Sambrisko error = ENOIOCTL; 3043157114Sscottl break; 3044157114Sscottl } 3045157114Sscottl break; 3046169451Sscottl case MFIIO_QUERY_DISK: 3047169451Sscottl { 3048169451Sscottl struct mfi_query_disk *qd; 3049169451Sscottl struct mfi_disk *ld; 3050169451Sscottl 3051169451Sscottl qd = (struct mfi_query_disk *)arg; 3052169451Sscottl mtx_lock(&sc->mfi_io_lock); 3053169451Sscottl TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 3054169451Sscottl if (ld->ld_id == qd->array_id) 3055169451Sscottl break; 3056169451Sscottl } 3057169451Sscottl if (ld == NULL) { 3058169451Sscottl qd->present = 0; 3059169451Sscottl mtx_unlock(&sc->mfi_io_lock); 3060169451Sscottl return (0); 3061169451Sscottl } 3062169451Sscottl qd->present = 1; 3063169451Sscottl if (ld->ld_flags & MFI_DISK_FLAGS_OPEN) 3064169451Sscottl qd->open = 1; 3065169451Sscottl bzero(qd->devname, SPECNAMELEN + 1); 3066169451Sscottl snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit); 3067169451Sscottl mtx_unlock(&sc->mfi_io_lock); 3068169451Sscottl break; 3069169451Sscottl } 3070164281Sambrisko case MFI_CMD: 3071233711Sambrisko#ifdef COMPAT_FREEBSD32 3072179392Sambrisko case MFI_CMD32: 3073179392Sambrisko#endif 3074177489Sambrisko { 3075177489Sambrisko devclass_t devclass; 3076164281Sambrisko ioc = (struct mfi_ioc_packet *)arg; 3077177489Sambrisko int adapter; 3078164281Sambrisko 3079177489Sambrisko adapter = ioc->mfi_adapter_no; 3080177489Sambrisko if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) { 3081177489Sambrisko devclass = devclass_find("mfi"); 3082177489Sambrisko sc = devclass_get_softc(devclass, adapter); 3083177489Sambrisko } 3084164281Sambrisko mtx_lock(&sc->mfi_io_lock); 3085164281Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 3086164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3087164281Sambrisko return (EBUSY); 3088164281Sambrisko } 3089164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3090171821Sjhb locked = 0; 3091164281Sambrisko 3092164281Sambrisko /* 3093164281Sambrisko * save off original context since copying from user 3094164281Sambrisko * will clobber some data 3095164281Sambrisko */ 3096164281Sambrisko context = cm->cm_frame->header.context; 3097233711Sambrisko cm->cm_frame->header.context = cm->cm_index; 3098164281Sambrisko 3099165225Sambrisko bcopy(ioc->mfi_frame.raw, cm->cm_frame, 3100233711Sambrisko 2 * MEGAMFI_FRAME_SIZE); 3101184897Sambrisko cm->cm_total_frame_size = (sizeof(union mfi_sgl) 3102184897Sambrisko * ioc->mfi_sge_count) + ioc->mfi_sgl_off; 3103233711Sambrisko cm->cm_frame->header.scsi_status = 0; 3104233711Sambrisko cm->cm_frame->header.pad0 = 0; 3105175897Sambrisko if (ioc->mfi_sge_count) { 3106175897Sambrisko cm->cm_sg = 3107175897Sambrisko (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off]; 3108175897Sambrisko } 3109233711Sambrisko sgl = cm->cm_sg; 3110175897Sambrisko cm->cm_flags = 0; 3111175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN) 3112175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN; 3113175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT) 3114175897Sambrisko cm->cm_flags |= MFI_CMD_DATAOUT; 3115175897Sambrisko /* Legacy app shim */ 3116175897Sambrisko if (cm->cm_flags == 0) 3117175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT; 3118164281Sambrisko cm->cm_len = cm->cm_frame->header.data_len; 3119225869Smav if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3120233711Sambrisko#ifdef COMPAT_FREEBSD32 3121225869Smav if (cmd == MFI_CMD) { 3122225869Smav#endif 3123225869Smav /* Native */ 3124225869Smav cm->cm_stp_len = ioc->mfi_sgl[0].iov_len; 3125233711Sambrisko#ifdef COMPAT_FREEBSD32 3126225869Smav } else { 3127225869Smav /* 32bit on 64bit */ 3128225869Smav ioc32 = (struct mfi_ioc_packet32 *)ioc; 3129225869Smav cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len; 3130225869Smav } 3131225869Smav#endif 3132225869Smav cm->cm_len += cm->cm_stp_len; 3133225869Smav } 3134184897Sambrisko if (cm->cm_len && 3135184897Sambrisko (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) { 3136175897Sambrisko cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF, 3137175897Sambrisko M_WAITOK | M_ZERO); 3138175897Sambrisko if (cm->cm_data == NULL) { 3139175897Sambrisko device_printf(sc->mfi_dev, "Malloc failed\n"); 3140175897Sambrisko goto out; 3141175897Sambrisko } 3142175897Sambrisko } else { 3143175897Sambrisko cm->cm_data = 0; 3144165225Sambrisko } 3145164281Sambrisko 3146164281Sambrisko /* restore header context */ 3147164281Sambrisko cm->cm_frame->header.context = context; 3148164281Sambrisko 3149233711Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3150233711Sambrisko res = mfi_stp_cmd(sc, cm, arg); 3151233711Sambrisko if (res != 0) 3152233711Sambrisko goto out; 3153233711Sambrisko } else { 3154233711Sambrisko temp = data; 3155233711Sambrisko if ((cm->cm_flags & MFI_CMD_DATAOUT) || 3156233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_STP)) { 3157233711Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 3158233711Sambrisko#ifdef COMPAT_FREEBSD32 3159233711Sambrisko if (cmd == MFI_CMD) { 3160225869Smav#endif 3161233711Sambrisko /* Native */ 3162233711Sambrisko addr = ioc->mfi_sgl[i].iov_base; 3163233711Sambrisko len = ioc->mfi_sgl[i].iov_len; 3164233711Sambrisko#ifdef COMPAT_FREEBSD32 3165233711Sambrisko } else { 3166233711Sambrisko /* 32bit on 64bit */ 3167233711Sambrisko ioc32 = (struct mfi_ioc_packet32 *)ioc; 3168233711Sambrisko addr = PTRIN(ioc32->mfi_sgl[i].iov_base); 3169233711Sambrisko len = ioc32->mfi_sgl[i].iov_len; 3170233711Sambrisko } 3171179392Sambrisko#endif 3172233711Sambrisko error = copyin(addr, temp, len); 3173233711Sambrisko if (error != 0) { 3174233711Sambrisko device_printf(sc->mfi_dev, 3175233711Sambrisko "Copy in failed\n"); 3176233711Sambrisko goto out; 3177233711Sambrisko } 3178233711Sambrisko temp = &temp[len]; 3179175897Sambrisko } 3180164281Sambrisko } 3181164281Sambrisko } 3182164281Sambrisko 3183171821Sjhb if (cm->cm_frame->header.cmd == MFI_CMD_DCMD) 3184233711Sambrisko locked = mfi_config_lock(sc, 3185233711Sambrisko cm->cm_frame->dcmd.opcode); 3186171821Sjhb 3187184933Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { 3188233711Sambrisko cm->cm_frame->pass.sense_addr_lo = 3189233711Sambrisko (uint32_t)cm->cm_sense_busaddr; 3190233711Sambrisko cm->cm_frame->pass.sense_addr_hi = 3191233711Sambrisko (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 3192184933Sambrisko } 3193164281Sambrisko mtx_lock(&sc->mfi_io_lock); 3194233711Sambrisko skip_pre_post = mfi_check_for_sscd (sc, cm); 3195233711Sambrisko if (!skip_pre_post) { 3196233711Sambrisko error = mfi_check_command_pre(sc, cm); 3197233711Sambrisko if (error) { 3198233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 3199233711Sambrisko goto out; 3200233711Sambrisko } 3201171821Sjhb } 3202170284Sambrisko if ((error = mfi_wait_command(sc, cm)) != 0) { 3203164281Sambrisko device_printf(sc->mfi_dev, 3204165225Sambrisko "Controller polled failed\n"); 3205164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3206164281Sambrisko goto out; 3207164281Sambrisko } 3208233711Sambrisko if (!skip_pre_post) { 3209233711Sambrisko mfi_check_command_post(sc, cm); 3210233711Sambrisko } 3211164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3212164281Sambrisko 3213233711Sambrisko if (cm->cm_frame->header.cmd != MFI_CMD_STP) { 3214233711Sambrisko temp = data; 3215233711Sambrisko if ((cm->cm_flags & MFI_CMD_DATAIN) || 3216233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_STP)) { 3217233711Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 3218233711Sambrisko#ifdef COMPAT_FREEBSD32 3219233711Sambrisko if (cmd == MFI_CMD) { 3220225869Smav#endif 3221233711Sambrisko /* Native */ 3222233711Sambrisko addr = ioc->mfi_sgl[i].iov_base; 3223233711Sambrisko len = ioc->mfi_sgl[i].iov_len; 3224233711Sambrisko#ifdef COMPAT_FREEBSD32 3225233711Sambrisko } else { 3226233711Sambrisko /* 32bit on 64bit */ 3227233711Sambrisko ioc32 = (struct mfi_ioc_packet32 *)ioc; 3228233711Sambrisko addr = PTRIN(ioc32->mfi_sgl[i].iov_base); 3229233711Sambrisko len = ioc32->mfi_sgl[i].iov_len; 3230233711Sambrisko } 3231179392Sambrisko#endif 3232233711Sambrisko error = copyout(temp, addr, len); 3233233711Sambrisko if (error != 0) { 3234233711Sambrisko device_printf(sc->mfi_dev, 3235233711Sambrisko "Copy out failed\n"); 3236233711Sambrisko goto out; 3237233711Sambrisko } 3238233711Sambrisko temp = &temp[len]; 3239175897Sambrisko } 3240164281Sambrisko } 3241164281Sambrisko } 3242164281Sambrisko 3243165225Sambrisko if (ioc->mfi_sense_len) { 3244184897Sambrisko /* get user-space sense ptr then copy out sense */ 3245225428Sbz bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off], 3246184897Sambrisko &sense_ptr.sense_ptr_data[0], 3247184897Sambrisko sizeof(sense_ptr.sense_ptr_data)); 3248233711Sambrisko#ifdef COMPAT_FREEBSD32 3249184974Sambrisko if (cmd != MFI_CMD) { 3250184974Sambrisko /* 3251184974Sambrisko * not 64bit native so zero out any address 3252184974Sambrisko * over 32bit */ 3253184975Sambrisko sense_ptr.addr.high = 0; 3254184974Sambrisko } 3255184974Sambrisko#endif 3256184897Sambrisko error = copyout(cm->cm_sense, sense_ptr.user_space, 3257165225Sambrisko ioc->mfi_sense_len); 3258164281Sambrisko if (error != 0) { 3259164281Sambrisko device_printf(sc->mfi_dev, 3260165225Sambrisko "Copy out failed\n"); 3261164281Sambrisko goto out; 3262164281Sambrisko } 3263164281Sambrisko } 3264164281Sambrisko 3265165225Sambrisko ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status; 3266164281Sambriskoout: 3267171821Sjhb mfi_config_unlock(sc, locked); 3268164281Sambrisko if (data) 3269164281Sambrisko free(data, M_MFIBUF); 3270233711Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3271233711Sambrisko for (i = 0; i < 2; i++) { 3272233711Sambrisko if (sc->kbuff_arr[i]) { 3273233711Sambrisko if (sc->mfi_kbuff_arr_busaddr != 0) 3274233711Sambrisko bus_dmamap_unload( 3275233711Sambrisko sc->mfi_kbuff_arr_dmat[i], 3276233711Sambrisko sc->mfi_kbuff_arr_dmamap[i] 3277233711Sambrisko ); 3278233711Sambrisko if (sc->kbuff_arr[i] != NULL) 3279233711Sambrisko bus_dmamem_free( 3280233711Sambrisko sc->mfi_kbuff_arr_dmat[i], 3281233711Sambrisko sc->kbuff_arr[i], 3282233711Sambrisko sc->mfi_kbuff_arr_dmamap[i] 3283233711Sambrisko ); 3284233711Sambrisko if (sc->mfi_kbuff_arr_dmat[i] != NULL) 3285233711Sambrisko bus_dma_tag_destroy( 3286233711Sambrisko sc->mfi_kbuff_arr_dmat[i]); 3287233711Sambrisko } 3288233711Sambrisko } 3289233711Sambrisko } 3290164281Sambrisko if (cm) { 3291164281Sambrisko mtx_lock(&sc->mfi_io_lock); 3292164281Sambrisko mfi_release_command(cm); 3293164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3294164281Sambrisko } 3295164281Sambrisko 3296164281Sambrisko break; 3297177489Sambrisko } 3298164281Sambrisko case MFI_SET_AEN: 3299164281Sambrisko aen = (struct mfi_ioc_aen *)arg; 3300164281Sambrisko error = mfi_aen_register(sc, aen->aen_seq_num, 3301164281Sambrisko aen->aen_class_locale); 3302164281Sambrisko 3303164281Sambrisko break; 3304164281Sambrisko case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */ 3305158737Sambrisko { 3306158737Sambrisko devclass_t devclass; 3307158737Sambrisko struct mfi_linux_ioc_packet l_ioc; 3308158737Sambrisko int adapter; 3309158737Sambrisko 3310158737Sambrisko devclass = devclass_find("mfi"); 3311158737Sambrisko if (devclass == NULL) 3312158737Sambrisko return (ENOENT); 3313158737Sambrisko 3314158737Sambrisko error = copyin(arg, &l_ioc, sizeof(l_ioc)); 3315158737Sambrisko if (error) 3316158737Sambrisko return (error); 3317158737Sambrisko adapter = l_ioc.lioc_adapter_no; 3318158737Sambrisko sc = devclass_get_softc(devclass, adapter); 3319158737Sambrisko if (sc == NULL) 3320158737Sambrisko return (ENOENT); 3321158737Sambrisko return (mfi_linux_ioctl_int(sc->mfi_cdev, 3322158737Sambrisko cmd, arg, flag, td)); 3323158737Sambrisko break; 3324158737Sambrisko } 3325164281Sambrisko case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */ 3326158737Sambrisko { 3327158737Sambrisko devclass_t devclass; 3328158737Sambrisko struct mfi_linux_ioc_aen l_aen; 3329158737Sambrisko int adapter; 3330158737Sambrisko 3331158737Sambrisko devclass = devclass_find("mfi"); 3332158737Sambrisko if (devclass == NULL) 3333158737Sambrisko return (ENOENT); 3334158737Sambrisko 3335158737Sambrisko error = copyin(arg, &l_aen, sizeof(l_aen)); 3336158737Sambrisko if (error) 3337158737Sambrisko return (error); 3338158737Sambrisko adapter = l_aen.laen_adapter_no; 3339158737Sambrisko sc = devclass_get_softc(devclass, adapter); 3340158737Sambrisko if (sc == NULL) 3341158737Sambrisko return (ENOENT); 3342158737Sambrisko return (mfi_linux_ioctl_int(sc->mfi_cdev, 3343158737Sambrisko cmd, arg, flag, td)); 3344158737Sambrisko break; 3345158737Sambrisko } 3346233711Sambrisko#ifdef COMPAT_FREEBSD32 3347178968Sscottl case MFIIO_PASSTHRU32: 3348238077Sjhb if (!SV_CURPROC_FLAG(SV_ILP32)) { 3349238077Sjhb error = ENOTTY; 3350238077Sjhb break; 3351238077Sjhb } 3352178968Sscottl iop_swab.ioc_frame = iop32->ioc_frame; 3353178968Sscottl iop_swab.buf_size = iop32->buf_size; 3354178968Sscottl iop_swab.buf = PTRIN(iop32->buf); 3355178968Sscottl iop = &iop_swab; 3356178968Sscottl /* FALLTHROUGH */ 3357178968Sscottl#endif 3358178968Sscottl case MFIIO_PASSTHRU: 3359178968Sscottl error = mfi_user_command(sc, iop); 3360233711Sambrisko#ifdef COMPAT_FREEBSD32 3361178968Sscottl if (cmd == MFIIO_PASSTHRU32) 3362178968Sscottl iop32->ioc_frame = iop_swab.ioc_frame; 3363178968Sscottl#endif 3364178968Sscottl break; 3365157114Sscottl default: 3366163398Sscottl device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); 3367238077Sjhb error = ENOTTY; 3368157114Sscottl break; 3369157114Sscottl } 3370157114Sscottl 3371157114Sscottl return (error); 3372157114Sscottl} 3373158737Sambrisko 3374158737Sambriskostatic int 3375192450Simpmfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 3376158737Sambrisko{ 3377158737Sambrisko struct mfi_softc *sc; 3378158737Sambrisko struct mfi_linux_ioc_packet l_ioc; 3379158737Sambrisko struct mfi_linux_ioc_aen l_aen; 3380158737Sambrisko struct mfi_command *cm = NULL; 3381158737Sambrisko struct mfi_aen *mfi_aen_entry; 3382184897Sambrisko union mfi_sense_ptr sense_ptr; 3383233711Sambrisko uint32_t context = 0; 3384158737Sambrisko uint8_t *data = NULL, *temp; 3385158737Sambrisko int i; 3386171821Sjhb int error, locked; 3387158737Sambrisko 3388158737Sambrisko sc = dev->si_drv1; 3389158737Sambrisko error = 0; 3390158737Sambrisko switch (cmd) { 3391164281Sambrisko case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */ 3392158737Sambrisko error = copyin(arg, &l_ioc, sizeof(l_ioc)); 3393158737Sambrisko if (error != 0) 3394158737Sambrisko return (error); 3395158737Sambrisko 3396158737Sambrisko if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) { 3397158737Sambrisko return (EINVAL); 3398158737Sambrisko } 3399158737Sambrisko 3400158737Sambrisko mtx_lock(&sc->mfi_io_lock); 3401158737Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 3402158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3403158737Sambrisko return (EBUSY); 3404158737Sambrisko } 3405158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3406171821Sjhb locked = 0; 3407158737Sambrisko 3408158737Sambrisko /* 3409158737Sambrisko * save off original context since copying from user 3410158737Sambrisko * will clobber some data 3411158737Sambrisko */ 3412158737Sambrisko context = cm->cm_frame->header.context; 3413158737Sambrisko 3414158737Sambrisko bcopy(l_ioc.lioc_frame.raw, cm->cm_frame, 3415175897Sambrisko 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */ 3416184897Sambrisko cm->cm_total_frame_size = (sizeof(union mfi_sgl) 3417184897Sambrisko * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off; 3418233711Sambrisko cm->cm_frame->header.scsi_status = 0; 3419233711Sambrisko cm->cm_frame->header.pad0 = 0; 3420175897Sambrisko if (l_ioc.lioc_sge_count) 3421175897Sambrisko cm->cm_sg = 3422175897Sambrisko (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off]; 3423175897Sambrisko cm->cm_flags = 0; 3424175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN) 3425175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN; 3426175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT) 3427175897Sambrisko cm->cm_flags |= MFI_CMD_DATAOUT; 3428158737Sambrisko cm->cm_len = cm->cm_frame->header.data_len; 3429184897Sambrisko if (cm->cm_len && 3430184897Sambrisko (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) { 3431175897Sambrisko cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF, 3432175897Sambrisko M_WAITOK | M_ZERO); 3433175897Sambrisko if (cm->cm_data == NULL) { 3434175897Sambrisko device_printf(sc->mfi_dev, "Malloc failed\n"); 3435175897Sambrisko goto out; 3436175897Sambrisko } 3437175897Sambrisko } else { 3438175897Sambrisko cm->cm_data = 0; 3439175897Sambrisko } 3440158737Sambrisko 3441158737Sambrisko /* restore header context */ 3442158737Sambrisko cm->cm_frame->header.context = context; 3443158737Sambrisko 3444158737Sambrisko temp = data; 3445175897Sambrisko if (cm->cm_flags & MFI_CMD_DATAOUT) { 3446175897Sambrisko for (i = 0; i < l_ioc.lioc_sge_count; i++) { 3447178968Sscottl error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base), 3448175897Sambrisko temp, 3449175897Sambrisko l_ioc.lioc_sgl[i].iov_len); 3450175897Sambrisko if (error != 0) { 3451175897Sambrisko device_printf(sc->mfi_dev, 3452175897Sambrisko "Copy in failed\n"); 3453175897Sambrisko goto out; 3454175897Sambrisko } 3455175897Sambrisko temp = &temp[l_ioc.lioc_sgl[i].iov_len]; 3456158737Sambrisko } 3457158737Sambrisko } 3458158737Sambrisko 3459171821Sjhb if (cm->cm_frame->header.cmd == MFI_CMD_DCMD) 3460171821Sjhb locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode); 3461171821Sjhb 3462184933Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { 3463233711Sambrisko cm->cm_frame->pass.sense_addr_lo = 3464233711Sambrisko (uint32_t)cm->cm_sense_busaddr; 3465233711Sambrisko cm->cm_frame->pass.sense_addr_hi = 3466233711Sambrisko (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 3467184933Sambrisko } 3468184933Sambrisko 3469163398Sscottl mtx_lock(&sc->mfi_io_lock); 3470171821Sjhb error = mfi_check_command_pre(sc, cm); 3471171821Sjhb if (error) { 3472171821Sjhb mtx_unlock(&sc->mfi_io_lock); 3473171821Sjhb goto out; 3474171821Sjhb } 3475171821Sjhb 3476170284Sambrisko if ((error = mfi_wait_command(sc, cm)) != 0) { 3477158737Sambrisko device_printf(sc->mfi_dev, 3478165225Sambrisko "Controller polled failed\n"); 3479163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3480158737Sambrisko goto out; 3481158737Sambrisko } 3482158737Sambrisko 3483171821Sjhb mfi_check_command_post(sc, cm); 3484163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3485158737Sambrisko 3486158737Sambrisko temp = data; 3487175897Sambrisko if (cm->cm_flags & MFI_CMD_DATAIN) { 3488175897Sambrisko for (i = 0; i < l_ioc.lioc_sge_count; i++) { 3489175897Sambrisko error = copyout(temp, 3490178968Sscottl PTRIN(l_ioc.lioc_sgl[i].iov_base), 3491175897Sambrisko l_ioc.lioc_sgl[i].iov_len); 3492175897Sambrisko if (error != 0) { 3493175897Sambrisko device_printf(sc->mfi_dev, 3494175897Sambrisko "Copy out failed\n"); 3495175897Sambrisko goto out; 3496175897Sambrisko } 3497175897Sambrisko temp = &temp[l_ioc.lioc_sgl[i].iov_len]; 3498158737Sambrisko } 3499158737Sambrisko } 3500158737Sambrisko 3501158737Sambrisko if (l_ioc.lioc_sense_len) { 3502184897Sambrisko /* get user-space sense ptr then copy out sense */ 3503184897Sambrisko bcopy(&((struct mfi_linux_ioc_packet*)arg) 3504184897Sambrisko ->lioc_frame.raw[l_ioc.lioc_sense_off], 3505184897Sambrisko &sense_ptr.sense_ptr_data[0], 3506184897Sambrisko sizeof(sense_ptr.sense_ptr_data)); 3507184974Sambrisko#ifdef __amd64__ 3508184974Sambrisko /* 3509184974Sambrisko * only 32bit Linux support so zero out any 3510184974Sambrisko * address over 32bit 3511184974Sambrisko */ 3512184975Sambrisko sense_ptr.addr.high = 0; 3513184974Sambrisko#endif 3514184897Sambrisko error = copyout(cm->cm_sense, sense_ptr.user_space, 3515158737Sambrisko l_ioc.lioc_sense_len); 3516158737Sambrisko if (error != 0) { 3517158737Sambrisko device_printf(sc->mfi_dev, 3518165225Sambrisko "Copy out failed\n"); 3519158737Sambrisko goto out; 3520158737Sambrisko } 3521158737Sambrisko } 3522158737Sambrisko 3523158737Sambrisko error = copyout(&cm->cm_frame->header.cmd_status, 3524158737Sambrisko &((struct mfi_linux_ioc_packet*)arg) 3525158737Sambrisko ->lioc_frame.hdr.cmd_status, 3526158737Sambrisko 1); 3527158737Sambrisko if (error != 0) { 3528158737Sambrisko device_printf(sc->mfi_dev, 3529165225Sambrisko "Copy out failed\n"); 3530158737Sambrisko goto out; 3531158737Sambrisko } 3532158737Sambrisko 3533158737Sambriskoout: 3534171821Sjhb mfi_config_unlock(sc, locked); 3535158737Sambrisko if (data) 3536158737Sambrisko free(data, M_MFIBUF); 3537158737Sambrisko if (cm) { 3538158737Sambrisko mtx_lock(&sc->mfi_io_lock); 3539158737Sambrisko mfi_release_command(cm); 3540158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3541158737Sambrisko } 3542158737Sambrisko 3543158737Sambrisko return (error); 3544164281Sambrisko case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */ 3545158737Sambrisko error = copyin(arg, &l_aen, sizeof(l_aen)); 3546158737Sambrisko if (error != 0) 3547158737Sambrisko return (error); 3548158737Sambrisko printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid); 3549158737Sambrisko mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF, 3550158737Sambrisko M_WAITOK); 3551163398Sscottl mtx_lock(&sc->mfi_io_lock); 3552158737Sambrisko if (mfi_aen_entry != NULL) { 3553158737Sambrisko mfi_aen_entry->p = curproc; 3554158737Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry, 3555158737Sambrisko aen_link); 3556158737Sambrisko } 3557158737Sambrisko error = mfi_aen_register(sc, l_aen.laen_seq_num, 3558158737Sambrisko l_aen.laen_class_locale); 3559158737Sambrisko 3560158737Sambrisko if (error != 0) { 3561158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 3562158737Sambrisko aen_link); 3563158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 3564158737Sambrisko } 3565163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3566158737Sambrisko 3567158737Sambrisko return (error); 3568158737Sambrisko default: 3569158737Sambrisko device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); 3570158737Sambrisko error = ENOENT; 3571158737Sambrisko break; 3572158737Sambrisko } 3573158737Sambrisko 3574158737Sambrisko return (error); 3575158737Sambrisko} 3576158737Sambrisko 3577158737Sambriskostatic int 3578158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td) 3579158737Sambrisko{ 3580158737Sambrisko struct mfi_softc *sc; 3581158737Sambrisko int revents = 0; 3582158737Sambrisko 3583158737Sambrisko sc = dev->si_drv1; 3584158737Sambrisko 3585158737Sambrisko if (poll_events & (POLLIN | POLLRDNORM)) { 3586163398Sscottl if (sc->mfi_aen_triggered != 0) { 3587158737Sambrisko revents |= poll_events & (POLLIN | POLLRDNORM); 3588163398Sscottl sc->mfi_aen_triggered = 0; 3589163398Sscottl } 3590158737Sambrisko if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) { 3591158737Sambrisko revents |= POLLERR; 3592158737Sambrisko } 3593158737Sambrisko } 3594158737Sambrisko 3595158737Sambrisko if (revents == 0) { 3596158737Sambrisko if (poll_events & (POLLIN | POLLRDNORM)) { 3597158737Sambrisko sc->mfi_poll_waiting = 1; 3598158737Sambrisko selrecord(td, &sc->mfi_select); 3599158737Sambrisko } 3600158737Sambrisko } 3601158737Sambrisko 3602158737Sambrisko return revents; 3603158737Sambrisko} 3604162619Sscottl 3605162619Sscottlstatic void 3606163398Sscottlmfi_dump_all(void) 3607163398Sscottl{ 3608163398Sscottl struct mfi_softc *sc; 3609163398Sscottl struct mfi_command *cm; 3610163398Sscottl devclass_t dc; 3611163398Sscottl time_t deadline; 3612163398Sscottl int timedout; 3613163398Sscottl int i; 3614163398Sscottl 3615163398Sscottl dc = devclass_find("mfi"); 3616163398Sscottl if (dc == NULL) { 3617163398Sscottl printf("No mfi dev class\n"); 3618163398Sscottl return; 3619163398Sscottl } 3620163398Sscottl 3621163398Sscottl for (i = 0; ; i++) { 3622163398Sscottl sc = devclass_get_softc(dc, i); 3623163398Sscottl if (sc == NULL) 3624163398Sscottl break; 3625163398Sscottl device_printf(sc->mfi_dev, "Dumping\n\n"); 3626163398Sscottl timedout = 0; 3627163398Sscottl deadline = time_uptime - MFI_CMD_TIMEOUT; 3628163398Sscottl mtx_lock(&sc->mfi_io_lock); 3629163398Sscottl TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) { 3630163398Sscottl if (cm->cm_timestamp < deadline) { 3631163398Sscottl device_printf(sc->mfi_dev, 3632233711Sambrisko "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 3633233711Sambrisko cm, (int)(time_uptime - cm->cm_timestamp)); 3634163398Sscottl MFI_PRINT_CMD(cm); 3635163398Sscottl timedout++; 3636163398Sscottl } 3637163398Sscottl } 3638163398Sscottl 3639163398Sscottl#if 0 3640163398Sscottl if (timedout) 3641163398Sscottl MFI_DUMP_CMDS(SC); 3642163398Sscottl#endif 3643163398Sscottl 3644163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3645163398Sscottl } 3646163398Sscottl 3647163398Sscottl return; 3648163398Sscottl} 3649163398Sscottl 3650163398Sscottlstatic void 3651162619Sscottlmfi_timeout(void *data) 3652162619Sscottl{ 3653162619Sscottl struct mfi_softc *sc = (struct mfi_softc *)data; 3654162619Sscottl struct mfi_command *cm; 3655162619Sscottl time_t deadline; 3656162619Sscottl int timedout = 0; 3657162619Sscottl 3658162619Sscottl deadline = time_uptime - MFI_CMD_TIMEOUT; 3659233711Sambrisko if (sc->adpreset == 0) { 3660233711Sambrisko if (!mfi_tbolt_reset(sc)) { 3661233711Sambrisko callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, mfi_timeout, sc); 3662233711Sambrisko return; 3663233711Sambrisko } 3664233711Sambrisko } 3665162619Sscottl mtx_lock(&sc->mfi_io_lock); 3666162619Sscottl TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) { 3667235014Sambrisko if (sc->mfi_aen_cm == cm || sc->mfi_map_sync_cm == cm) 3668162688Sscottl continue; 3669235014Sambrisko if (cm->cm_timestamp < deadline) { 3670233711Sambrisko if (sc->adpreset != 0 && sc->issuepend_done == 0) { 3671233711Sambrisko cm->cm_timestamp = time_uptime; 3672233711Sambrisko } else { 3673233711Sambrisko device_printf(sc->mfi_dev, 3674233711Sambrisko "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 3675233711Sambrisko cm, (int)(time_uptime - cm->cm_timestamp) 3676233711Sambrisko ); 3677233711Sambrisko MFI_PRINT_CMD(cm); 3678233711Sambrisko MFI_VALIDATE_CMD(sc, cm); 3679233711Sambrisko timedout++; 3680233711Sambrisko } 3681162619Sscottl } 3682162619Sscottl } 3683162619Sscottl 3684162619Sscottl#if 0 3685162619Sscottl if (timedout) 3686162619Sscottl MFI_DUMP_CMDS(SC); 3687162619Sscottl#endif 3688162619Sscottl 3689162619Sscottl mtx_unlock(&sc->mfi_io_lock); 3690162619Sscottl 3691162619Sscottl callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, 3692162619Sscottl mfi_timeout, sc); 3693162619Sscottl 3694163398Sscottl if (0) 3695163398Sscottl mfi_dump_all(); 3696162619Sscottl return; 3697162619Sscottl} 3698