mfi.c revision 240962
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 240962 2012-09-26 14:14:06Z jhb $"); 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 *); 111158737Sambriskostatic 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); 377233711Sambrisko TAILQ_INIT(&sc->mfi_evt_queue); 378233711Sambrisko TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc); 379235014Sambrisko TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc); 380158737Sambrisko TAILQ_INIT(&sc->mfi_aen_pids); 381169611Sscottl TAILQ_INIT(&sc->mfi_cam_ccbq); 382157114Sscottl 383157114Sscottl mfi_initq_free(sc); 384157114Sscottl mfi_initq_ready(sc); 385157114Sscottl mfi_initq_busy(sc); 386157114Sscottl mfi_initq_bio(sc); 387157114Sscottl 388233711Sambrisko sc->adpreset = 0; 389233711Sambrisko sc->last_seq_num = 0; 390233711Sambrisko sc->disableOnlineCtrlReset = 1; 391233711Sambrisko sc->issuepend_done = 1; 392233711Sambrisko sc->hw_crit_error = 0; 393233711Sambrisko 394171980Sscottl if (sc->mfi_flags & MFI_FLAGS_1064R) { 395171980Sscottl sc->mfi_enable_intr = mfi_enable_intr_xscale; 396171980Sscottl sc->mfi_read_fw_status = mfi_read_fw_status_xscale; 397171980Sscottl sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale; 398171980Sscottl sc->mfi_issue_cmd = mfi_issue_cmd_xscale; 399233711Sambrisko } else if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 400233711Sambrisko sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc; 401233711Sambrisko sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc; 402233711Sambrisko sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc; 403233711Sambrisko sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc; 404233711Sambrisko sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc; 405233711Sambrisko sc->mfi_adp_reset = mfi_tbolt_adp_reset; 406233711Sambrisko sc->mfi_tbolt = 1; 407233711Sambrisko TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh); 408233711Sambrisko } else { 409171980Sscottl sc->mfi_enable_intr = mfi_enable_intr_ppc; 410233711Sambrisko sc->mfi_read_fw_status = mfi_read_fw_status_ppc; 411171980Sscottl sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc; 412171980Sscottl sc->mfi_issue_cmd = mfi_issue_cmd_ppc; 413171980Sscottl } 414171980Sscottl 415171980Sscottl 416157114Sscottl /* Before we get too far, see if the firmware is working */ 417157114Sscottl if ((error = mfi_transition_firmware(sc)) != 0) { 418157114Sscottl device_printf(sc->mfi_dev, "Firmware not in READY state, " 419157114Sscottl "error %d\n", error); 420157114Sscottl return (ENXIO); 421157114Sscottl } 422157114Sscottl 423233711Sambrisko /* Start: LSIP200113393 */ 424233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 425233711Sambrisko 1, 0, /* algnmnt, boundary */ 426233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 427233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 428233711Sambrisko NULL, NULL, /* filter, filterarg */ 429233711Sambrisko MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsize */ 430233711Sambrisko 1, /* msegments */ 431233711Sambrisko MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsegsize */ 432233711Sambrisko 0, /* flags */ 433233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 434233711Sambrisko &sc->verbuf_h_dmat)) { 435233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n"); 436233711Sambrisko return (ENOMEM); 437233711Sambrisko } 438233711Sambrisko if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf, 439233711Sambrisko BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) { 440233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n"); 441233711Sambrisko return (ENOMEM); 442233711Sambrisko } 443233711Sambrisko bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t)); 444233711Sambrisko bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap, 445233711Sambrisko sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t), 446233711Sambrisko mfi_addr_cb, &sc->verbuf_h_busaddr, 0); 447233711Sambrisko /* End: LSIP200113393 */ 448233711Sambrisko 449157114Sscottl /* 450157114Sscottl * Get information needed for sizing the contiguous memory for the 451157114Sscottl * frame pool. Size down the sgl parameter since we know that 452157114Sscottl * we will never need more than what's required for MAXPHYS. 453157114Sscottl * It would be nice if these constants were available at runtime 454157114Sscottl * instead of compile time. 455157114Sscottl */ 456171980Sscottl status = sc->mfi_read_fw_status(sc); 457157114Sscottl sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK; 458162458Sscottl max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16; 459195534Sscottl sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1)); 460157114Sscottl 461233711Sambrisko /* ThunderBolt Support get the contiguous memory */ 462233711Sambrisko 463233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 464233711Sambrisko mfi_tbolt_init_globals(sc); 465233711Sambrisko device_printf(sc->mfi_dev, "MaxCmd = %x MaxSgl = %x state = %x \n", 466233711Sambrisko sc->mfi_max_fw_cmds, sc->mfi_max_sge, status); 467233711Sambrisko tb_mem_size = mfi_tbolt_get_memory_requirement(sc); 468233711Sambrisko 469233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 470233711Sambrisko 1, 0, /* algnmnt, boundary */ 471233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 472233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 473233711Sambrisko NULL, NULL, /* filter, filterarg */ 474233711Sambrisko tb_mem_size, /* maxsize */ 475233711Sambrisko 1, /* msegments */ 476233711Sambrisko tb_mem_size, /* maxsegsize */ 477233711Sambrisko 0, /* flags */ 478233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 479233711Sambrisko &sc->mfi_tb_dmat)) { 480233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n"); 481233711Sambrisko return (ENOMEM); 482233711Sambrisko } 483233711Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool, 484233711Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) { 485233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 486233711Sambrisko return (ENOMEM); 487233711Sambrisko } 488233711Sambrisko bzero(sc->request_message_pool, tb_mem_size); 489233711Sambrisko bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap, 490233711Sambrisko sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0); 491233711Sambrisko 492233711Sambrisko /* For ThunderBolt memory init */ 493233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 494233711Sambrisko 0x100, 0, /* alignmnt, boundary */ 495233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 496233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 497233711Sambrisko NULL, NULL, /* filter, filterarg */ 498233711Sambrisko MFI_FRAME_SIZE, /* maxsize */ 499233711Sambrisko 1, /* msegments */ 500233711Sambrisko MFI_FRAME_SIZE, /* maxsegsize */ 501233711Sambrisko 0, /* flags */ 502233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 503233711Sambrisko &sc->mfi_tb_init_dmat)) { 504233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n"); 505233711Sambrisko return (ENOMEM); 506233711Sambrisko } 507233711Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init, 508233711Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) { 509233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate init memory\n"); 510233711Sambrisko return (ENOMEM); 511233711Sambrisko } 512233711Sambrisko bzero(sc->mfi_tb_init, MFI_FRAME_SIZE); 513233711Sambrisko bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap, 514233711Sambrisko sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb, 515233711Sambrisko &sc->mfi_tb_init_busaddr, 0); 516233711Sambrisko if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool, 517233711Sambrisko tb_mem_size)) { 518233711Sambrisko device_printf(sc->mfi_dev, 519233711Sambrisko "Thunderbolt pool preparation error\n"); 520233711Sambrisko return 0; 521233711Sambrisko } 522233711Sambrisko 523233711Sambrisko /* 524233711Sambrisko Allocate DMA memory mapping for MPI2 IOC Init descriptor, 525233711Sambrisko we are taking it diffrent from what we have allocated for Request 526233711Sambrisko and reply descriptors to avoid confusion later 527233711Sambrisko */ 528233711Sambrisko tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST); 529233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 530233711Sambrisko 1, 0, /* algnmnt, boundary */ 531233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 532233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 533233711Sambrisko NULL, NULL, /* filter, filterarg */ 534233711Sambrisko tb_mem_size, /* maxsize */ 535233711Sambrisko 1, /* msegments */ 536233711Sambrisko tb_mem_size, /* maxsegsize */ 537233711Sambrisko 0, /* flags */ 538233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 539233711Sambrisko &sc->mfi_tb_ioc_init_dmat)) { 540233711Sambrisko device_printf(sc->mfi_dev, 541233711Sambrisko "Cannot allocate comms DMA tag\n"); 542233711Sambrisko return (ENOMEM); 543233711Sambrisko } 544233711Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat, 545233711Sambrisko (void **)&sc->mfi_tb_ioc_init_desc, 546233711Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) { 547233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 548233711Sambrisko return (ENOMEM); 549233711Sambrisko } 550233711Sambrisko bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size); 551233711Sambrisko bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap, 552233711Sambrisko sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb, 553233711Sambrisko &sc->mfi_tb_ioc_init_busaddr, 0); 554233711Sambrisko } 555157114Sscottl /* 556157114Sscottl * Create the dma tag for data buffers. Used both for block I/O 557157114Sscottl * and for various internal data queries. 558157114Sscottl */ 559157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 560157114Sscottl 1, 0, /* algnmnt, boundary */ 561157114Sscottl BUS_SPACE_MAXADDR, /* lowaddr */ 562157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 563157114Sscottl NULL, NULL, /* filter, filterarg */ 564157114Sscottl BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 565162458Sscottl sc->mfi_max_sge, /* nsegments */ 566157114Sscottl BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 567157114Sscottl BUS_DMA_ALLOCNOW, /* flags */ 568157114Sscottl busdma_lock_mutex, /* lockfunc */ 569157114Sscottl &sc->mfi_io_lock, /* lockfuncarg */ 570157114Sscottl &sc->mfi_buffer_dmat)) { 571157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n"); 572157114Sscottl return (ENOMEM); 573157114Sscottl } 574157114Sscottl 575157114Sscottl /* 576157114Sscottl * Allocate DMA memory for the comms queues. Keep it under 4GB for 577157114Sscottl * efficiency. The mfi_hwcomms struct includes space for 1 reply queue 578157114Sscottl * entry, so the calculated size here will be will be 1 more than 579157114Sscottl * mfi_max_fw_cmds. This is apparently a requirement of the hardware. 580157114Sscottl */ 581157114Sscottl commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) + 582157114Sscottl sizeof(struct mfi_hwcomms); 583157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 584157114Sscottl 1, 0, /* algnmnt, boundary */ 585157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 586157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 587157114Sscottl NULL, NULL, /* filter, filterarg */ 588157114Sscottl commsz, /* maxsize */ 589157114Sscottl 1, /* msegments */ 590157114Sscottl commsz, /* maxsegsize */ 591157114Sscottl 0, /* flags */ 592157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 593157114Sscottl &sc->mfi_comms_dmat)) { 594157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n"); 595157114Sscottl return (ENOMEM); 596157114Sscottl } 597157114Sscottl if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms, 598157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) { 599157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 600157114Sscottl return (ENOMEM); 601157114Sscottl } 602157114Sscottl bzero(sc->mfi_comms, commsz); 603157114Sscottl bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap, 604233711Sambrisko sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0); 605157114Sscottl /* 606157114Sscottl * Allocate DMA memory for the command frames. Keep them in the 607162458Sscottl * lower 4GB for efficiency. Calculate the size of the commands at 608162458Sscottl * the same time; each command is one 64 byte frame plus a set of 609162458Sscottl * additional frames for holding sg lists or other data. 610157114Sscottl * The assumption here is that the SG list will start at the second 611162458Sscottl * frame and not use the unused bytes in the first frame. While this 612162458Sscottl * isn't technically correct, it simplifies the calculation and allows 613162458Sscottl * for command frames that might be larger than an mfi_io_frame. 614157114Sscottl */ 615157114Sscottl if (sizeof(bus_addr_t) == 8) { 616162458Sscottl sc->mfi_sge_size = sizeof(struct mfi_sg64); 617157114Sscottl sc->mfi_flags |= MFI_FLAGS_SG64; 618157114Sscottl } else { 619162458Sscottl sc->mfi_sge_size = sizeof(struct mfi_sg32); 620157114Sscottl } 621233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) 622233711Sambrisko sc->mfi_sge_size = sizeof(struct mfi_sg_skinny); 623162458Sscottl frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2; 624162458Sscottl sc->mfi_cmd_size = frames * MFI_FRAME_SIZE; 625162458Sscottl framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds; 626157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 627157114Sscottl 64, 0, /* algnmnt, boundary */ 628157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 629157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 630157114Sscottl NULL, NULL, /* filter, filterarg */ 631157114Sscottl framessz, /* maxsize */ 632157114Sscottl 1, /* nsegments */ 633157114Sscottl framessz, /* maxsegsize */ 634157114Sscottl 0, /* flags */ 635157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 636157114Sscottl &sc->mfi_frames_dmat)) { 637157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n"); 638157114Sscottl return (ENOMEM); 639157114Sscottl } 640157114Sscottl if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames, 641157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) { 642157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate frames memory\n"); 643157114Sscottl return (ENOMEM); 644157114Sscottl } 645157114Sscottl bzero(sc->mfi_frames, framessz); 646157114Sscottl bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap, 647233711Sambrisko sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0); 648157114Sscottl /* 649157114Sscottl * Allocate DMA memory for the frame sense data. Keep them in the 650157114Sscottl * lower 4GB for efficiency 651157114Sscottl */ 652157114Sscottl sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN; 653157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 654157114Sscottl 4, 0, /* algnmnt, boundary */ 655157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 656157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 657157114Sscottl NULL, NULL, /* filter, filterarg */ 658157114Sscottl sensesz, /* maxsize */ 659157114Sscottl 1, /* nsegments */ 660157114Sscottl sensesz, /* maxsegsize */ 661157114Sscottl 0, /* flags */ 662157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 663157114Sscottl &sc->mfi_sense_dmat)) { 664157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n"); 665157114Sscottl return (ENOMEM); 666157114Sscottl } 667157114Sscottl if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense, 668157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) { 669157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate sense memory\n"); 670157114Sscottl return (ENOMEM); 671157114Sscottl } 672157114Sscottl bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap, 673233711Sambrisko sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0); 674157114Sscottl if ((error = mfi_alloc_commands(sc)) != 0) 675157114Sscottl return (error); 676157114Sscottl 677233711Sambrisko /* Before moving the FW to operational state, check whether 678233711Sambrisko * hostmemory is required by the FW or not 679233711Sambrisko */ 680157114Sscottl 681233711Sambrisko /* ThunderBolt MFI_IOC2 INIT */ 682233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 683233711Sambrisko sc->mfi_disable_intr(sc); 684233711Sambrisko if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) { 685233711Sambrisko device_printf(sc->mfi_dev, 686233711Sambrisko "TB Init has failed with error %d\n",error); 687233711Sambrisko return error; 688233711Sambrisko } 689157114Sscottl 690233711Sambrisko if ((error = mfi_tbolt_alloc_cmd(sc)) != 0) 691233711Sambrisko return error; 692233711Sambrisko if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, 693233711Sambrisko INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc, 694233711Sambrisko &sc->mfi_intr)) { 695233711Sambrisko device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); 696233711Sambrisko return (EINVAL); 697233711Sambrisko } 698233711Sambrisko sc->mfi_enable_intr(sc); 699233711Sambrisko } else { 700233711Sambrisko if ((error = mfi_comms_init(sc)) != 0) 701233711Sambrisko return (error); 702157114Sscottl 703233711Sambrisko if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, 704233711Sambrisko INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) { 705233711Sambrisko device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); 706233711Sambrisko return (EINVAL); 707233711Sambrisko } 708233711Sambrisko sc->mfi_enable_intr(sc); 709157114Sscottl } 710233711Sambrisko if ((error = mfi_get_controller_info(sc)) != 0) 711233711Sambrisko return (error); 712233711Sambrisko sc->disableOnlineCtrlReset = 0; 713157114Sscottl 714157114Sscottl /* Register a config hook to probe the bus for arrays */ 715157114Sscottl sc->mfi_ich.ich_func = mfi_startup; 716157114Sscottl sc->mfi_ich.ich_arg = sc; 717157114Sscottl if (config_intrhook_establish(&sc->mfi_ich) != 0) { 718157114Sscottl device_printf(sc->mfi_dev, "Cannot establish configuration " 719157114Sscottl "hook\n"); 720157114Sscottl return (EINVAL); 721157114Sscottl } 722233711Sambrisko if ((error = mfi_aen_setup(sc, 0), 0) != 0) { 723233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 724233711Sambrisko return (error); 725233711Sambrisko } 726157114Sscottl 727157114Sscottl /* 728157114Sscottl * Register a shutdown handler. 729157114Sscottl */ 730157114Sscottl if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown, 731157114Sscottl sc, SHUTDOWN_PRI_DEFAULT)) == NULL) { 732157114Sscottl device_printf(sc->mfi_dev, "Warning: shutdown event " 733157114Sscottl "registration failed\n"); 734157114Sscottl } 735157114Sscottl 736157114Sscottl /* 737157114Sscottl * Create the control device for doing management 738157114Sscottl */ 739157114Sscottl unit = device_get_unit(sc->mfi_dev); 740157114Sscottl sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR, 741157114Sscottl 0640, "mfi%d", unit); 742158737Sambrisko if (unit == 0) 743158737Sambrisko make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node"); 744157114Sscottl if (sc->mfi_cdev != NULL) 745157114Sscottl sc->mfi_cdev->si_drv1 = sc; 746171821Sjhb SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev), 747171821Sjhb SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), 748171821Sjhb OID_AUTO, "delete_busy_volumes", CTLFLAG_RW, 749171821Sjhb &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes"); 750171821Sjhb SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev), 751171821Sjhb SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), 752171821Sjhb OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW, 753171821Sjhb &sc->mfi_keep_deleted_volumes, 0, 754171821Sjhb "Don't detach the mfid device for a busy volume that is deleted"); 755157114Sscottl 756169611Sscottl device_add_child(sc->mfi_dev, "mfip", -1); 757169611Sscottl bus_generic_attach(sc->mfi_dev); 758169611Sscottl 759162619Sscottl /* Start the timeout watchdog */ 760178250Skris callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE); 761162619Sscottl callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, 762162619Sscottl mfi_timeout, sc); 763162619Sscottl 764235014Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 765235014Sambrisko mfi_tbolt_sync_map_info(sc); 766235014Sambrisko } 767235014Sambrisko 768157114Sscottl return (0); 769157114Sscottl} 770157114Sscottl 771157114Sscottlstatic int 772157114Sscottlmfi_alloc_commands(struct mfi_softc *sc) 773157114Sscottl{ 774157114Sscottl struct mfi_command *cm; 775157114Sscottl int i, ncmds; 776157114Sscottl 777157114Sscottl /* 778157114Sscottl * XXX Should we allocate all the commands up front, or allocate on 779157114Sscottl * demand later like 'aac' does? 780157114Sscottl */ 781178968Sscottl ncmds = MIN(mfi_max_cmds, sc->mfi_max_fw_cmds); 782178968Sscottl if (bootverbose) 783178968Sscottl device_printf(sc->mfi_dev, "Max fw cmds= %d, sizing driver " 784178968Sscottl "pool to %d\n", sc->mfi_max_fw_cmds, ncmds); 785178968Sscottl 786157114Sscottl sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF, 787157114Sscottl M_WAITOK | M_ZERO); 788157114Sscottl 789157114Sscottl for (i = 0; i < ncmds; i++) { 790157114Sscottl cm = &sc->mfi_commands[i]; 791158737Sambrisko cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames + 792162458Sscottl sc->mfi_cmd_size * i); 793157114Sscottl cm->cm_frame_busaddr = sc->mfi_frames_busaddr + 794162458Sscottl sc->mfi_cmd_size * i; 795157114Sscottl cm->cm_frame->header.context = i; 796157114Sscottl cm->cm_sense = &sc->mfi_sense[i]; 797157114Sscottl cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i; 798157114Sscottl cm->cm_sc = sc; 799162619Sscottl cm->cm_index = i; 800157114Sscottl if (bus_dmamap_create(sc->mfi_buffer_dmat, 0, 801233711Sambrisko &cm->cm_dmamap) == 0) { 802233711Sambrisko mtx_lock(&sc->mfi_io_lock); 803157114Sscottl mfi_release_command(cm); 804233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 805233711Sambrisko } 806157114Sscottl else 807157114Sscottl break; 808157114Sscottl sc->mfi_total_cmds++; 809157114Sscottl } 810157114Sscottl 811157114Sscottl return (0); 812157114Sscottl} 813157114Sscottl 814169611Sscottlvoid 815157114Sscottlmfi_release_command(struct mfi_command *cm) 816157114Sscottl{ 817163398Sscottl struct mfi_frame_header *hdr; 818157114Sscottl uint32_t *hdr_data; 819157114Sscottl 820233711Sambrisko mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED); 821233711Sambrisko 822157114Sscottl /* 823157114Sscottl * Zero out the important fields of the frame, but make sure the 824165727Sscottl * context field is preserved. For efficiency, handle the fields 825165727Sscottl * as 32 bit words. Clear out the first S/G entry too for safety. 826157114Sscottl */ 827163398Sscottl hdr = &cm->cm_frame->header; 828175897Sambrisko if (cm->cm_data != NULL && hdr->sg_count) { 829163398Sscottl cm->cm_sg->sg32[0].len = 0; 830163398Sscottl cm->cm_sg->sg32[0].addr = 0; 831163398Sscottl } 832165727Sscottl 833165727Sscottl hdr_data = (uint32_t *)cm->cm_frame; 834165727Sscottl hdr_data[0] = 0; /* cmd, sense_len, cmd_status, scsi_status */ 835165727Sscottl hdr_data[1] = 0; /* target_id, lun_id, cdb_len, sg_count */ 836165727Sscottl hdr_data[4] = 0; /* flags, timeout */ 837165727Sscottl hdr_data[5] = 0; /* data_len */ 838165727Sscottl 839157114Sscottl cm->cm_extra_frames = 0; 840157114Sscottl cm->cm_flags = 0; 841157114Sscottl cm->cm_complete = NULL; 842157114Sscottl cm->cm_private = NULL; 843169611Sscottl cm->cm_data = NULL; 844157114Sscottl cm->cm_sg = 0; 845157114Sscottl cm->cm_total_frame_size = 0; 846233711Sambrisko cm->retry_for_fw_reset = 0; 847163398Sscottl 848157114Sscottl mfi_enqueue_free(cm); 849157114Sscottl} 850157114Sscottl 851235014Sambriskoint 852233711Sambriskomfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, 853233711Sambrisko uint32_t opcode, void **bufp, size_t bufsize) 854159806Sps{ 855159806Sps struct mfi_command *cm; 856159806Sps struct mfi_dcmd_frame *dcmd; 857159806Sps void *buf = NULL; 858233711Sambrisko uint32_t context = 0; 859233711Sambrisko 860159806Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 861233711Sambrisko 862159806Sps cm = mfi_dequeue_free(sc); 863159806Sps if (cm == NULL) 864159806Sps return (EBUSY); 865159806Sps 866233711Sambrisko /* Zero out the MFI frame */ 867233711Sambrisko context = cm->cm_frame->header.context; 868233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 869233711Sambrisko cm->cm_frame->header.context = context; 870233711Sambrisko 871159806Sps if ((bufsize > 0) && (bufp != NULL)) { 872159806Sps if (*bufp == NULL) { 873159806Sps buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO); 874159806Sps if (buf == NULL) { 875159806Sps mfi_release_command(cm); 876159806Sps return (ENOMEM); 877159806Sps } 878159806Sps *bufp = buf; 879159806Sps } else { 880159806Sps buf = *bufp; 881159806Sps } 882159806Sps } 883159806Sps 884159806Sps dcmd = &cm->cm_frame->dcmd; 885159806Sps bzero(dcmd->mbox, MFI_MBOX_SIZE); 886159806Sps dcmd->header.cmd = MFI_CMD_DCMD; 887159806Sps dcmd->header.timeout = 0; 888159806Sps dcmd->header.flags = 0; 889159806Sps dcmd->header.data_len = bufsize; 890233711Sambrisko dcmd->header.scsi_status = 0; 891159806Sps dcmd->opcode = opcode; 892159806Sps cm->cm_sg = &dcmd->sgl; 893159806Sps cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 894159806Sps cm->cm_flags = 0; 895159806Sps cm->cm_data = buf; 896159806Sps cm->cm_private = buf; 897159806Sps cm->cm_len = bufsize; 898159806Sps 899159806Sps *cmp = cm; 900159806Sps if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL)) 901159806Sps *bufp = buf; 902159806Sps return (0); 903159806Sps} 904159806Sps 905159806Spsstatic int 906157114Sscottlmfi_comms_init(struct mfi_softc *sc) 907157114Sscottl{ 908157114Sscottl struct mfi_command *cm; 909157114Sscottl struct mfi_init_frame *init; 910157114Sscottl struct mfi_init_qinfo *qinfo; 911157114Sscottl int error; 912233711Sambrisko uint32_t context = 0; 913157114Sscottl 914163398Sscottl mtx_lock(&sc->mfi_io_lock); 915157114Sscottl if ((cm = mfi_dequeue_free(sc)) == NULL) 916157114Sscottl return (EBUSY); 917157114Sscottl 918233711Sambrisko /* Zero out the MFI frame */ 919233711Sambrisko context = cm->cm_frame->header.context; 920233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 921233711Sambrisko cm->cm_frame->header.context = context; 922233711Sambrisko 923157114Sscottl /* 924157114Sscottl * Abuse the SG list area of the frame to hold the init_qinfo 925157114Sscottl * object; 926157114Sscottl */ 927157114Sscottl init = &cm->cm_frame->init; 928157114Sscottl qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE); 929157114Sscottl 930157114Sscottl bzero(qinfo, sizeof(struct mfi_init_qinfo)); 931157114Sscottl qinfo->rq_entries = sc->mfi_max_fw_cmds + 1; 932157114Sscottl qinfo->rq_addr_lo = sc->mfi_comms_busaddr + 933157114Sscottl offsetof(struct mfi_hwcomms, hw_reply_q); 934157114Sscottl qinfo->pi_addr_lo = sc->mfi_comms_busaddr + 935157114Sscottl offsetof(struct mfi_hwcomms, hw_pi); 936157114Sscottl qinfo->ci_addr_lo = sc->mfi_comms_busaddr + 937157114Sscottl offsetof(struct mfi_hwcomms, hw_ci); 938157114Sscottl 939157114Sscottl init->header.cmd = MFI_CMD_INIT; 940157114Sscottl init->header.data_len = sizeof(struct mfi_init_qinfo); 941157114Sscottl init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE; 942164375Sscottl cm->cm_data = NULL; 943164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 944157114Sscottl 945164375Sscottl if ((error = mfi_mapcmd(sc, cm)) != 0) { 946157114Sscottl device_printf(sc->mfi_dev, "failed to send init command\n"); 947163398Sscottl mtx_unlock(&sc->mfi_io_lock); 948157114Sscottl return (error); 949157114Sscottl } 950157114Sscottl mfi_release_command(cm); 951163398Sscottl mtx_unlock(&sc->mfi_io_lock); 952157114Sscottl 953157114Sscottl return (0); 954157114Sscottl} 955157114Sscottl 956157114Sscottlstatic int 957157114Sscottlmfi_get_controller_info(struct mfi_softc *sc) 958157114Sscottl{ 959159806Sps struct mfi_command *cm = NULL; 960159806Sps struct mfi_ctrl_info *ci = NULL; 961157114Sscottl uint32_t max_sectors_1, max_sectors_2; 962157114Sscottl int error; 963157114Sscottl 964159806Sps mtx_lock(&sc->mfi_io_lock); 965159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO, 966159806Sps (void **)&ci, sizeof(*ci)); 967159806Sps if (error) 968159806Sps goto out; 969157114Sscottl cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 970157114Sscottl 971157114Sscottl if ((error = mfi_mapcmd(sc, cm)) != 0) { 972157114Sscottl device_printf(sc->mfi_dev, "Failed to get controller info\n"); 973162458Sscottl sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE / 974157114Sscottl MFI_SECTOR_LEN; 975159806Sps error = 0; 976159806Sps goto out; 977157114Sscottl } 978157114Sscottl 979157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 980157114Sscottl BUS_DMASYNC_POSTREAD); 981157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 982157114Sscottl 983233711Sambrisko max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io; 984157114Sscottl max_sectors_2 = ci->max_request_size; 985157114Sscottl sc->mfi_max_io = min(max_sectors_1, max_sectors_2); 986233711Sambrisko sc->disableOnlineCtrlReset = 987233711Sambrisko ci->properties.OnOffProperties.disableOnlineCtrlReset; 988157114Sscottl 989159806Spsout: 990159806Sps if (ci) 991159806Sps free(ci, M_MFIBUF); 992159806Sps if (cm) 993159806Sps mfi_release_command(cm); 994159806Sps mtx_unlock(&sc->mfi_io_lock); 995157114Sscottl return (error); 996157114Sscottl} 997157114Sscottl 998157114Sscottlstatic int 999159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state) 1000158737Sambrisko{ 1001159812Sps struct mfi_command *cm = NULL; 1002158737Sambrisko int error; 1003158737Sambrisko 1004233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1005159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO, 1006159806Sps (void **)log_state, sizeof(**log_state)); 1007159806Sps if (error) 1008159806Sps goto out; 1009159810Sps cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1010158737Sambrisko 1011158737Sambrisko if ((error = mfi_mapcmd(sc, cm)) != 0) { 1012159802Sps device_printf(sc->mfi_dev, "Failed to get log state\n"); 1013159806Sps goto out; 1014158737Sambrisko } 1015158737Sambrisko 1016158737Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1017158737Sambrisko BUS_DMASYNC_POSTREAD); 1018158737Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1019158737Sambrisko 1020159806Spsout: 1021159812Sps if (cm) 1022159812Sps mfi_release_command(cm); 1023233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1024158737Sambrisko 1025158737Sambrisko return (error); 1026158737Sambrisko} 1027158737Sambrisko 1028233711Sambriskoint 1029158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start) 1030158737Sambrisko{ 1031159806Sps struct mfi_evt_log_state *log_state = NULL; 1032158737Sambrisko union mfi_evt class_locale; 1033158737Sambrisko int error = 0; 1034158737Sambrisko uint32_t seq; 1035158737Sambrisko 1036158737Sambrisko class_locale.members.reserved = 0; 1037162118Sambrisko class_locale.members.locale = mfi_event_locale; 1038222589Semaste class_locale.members.evt_class = mfi_event_class; 1039158737Sambrisko 1040158737Sambrisko if (seq_start == 0) { 1041158737Sambrisko error = mfi_get_log_state(sc, &log_state); 1042233711Sambrisko sc->mfi_boot_seq_num = log_state->boot_seq_num; 1043159806Sps if (error) { 1044159806Sps if (log_state) 1045159806Sps free(log_state, M_MFIBUF); 1046158737Sambrisko return (error); 1047159806Sps } 1048180037Sjhb 1049180037Sjhb /* 1050180037Sjhb * Walk through any events that fired since the last 1051180037Sjhb * shutdown. 1052180037Sjhb */ 1053180037Sjhb mfi_parse_entries(sc, log_state->shutdown_seq_num, 1054180037Sjhb log_state->newest_seq_num); 1055180037Sjhb seq = log_state->newest_seq_num; 1056158737Sambrisko } else 1057158737Sambrisko seq = seq_start; 1058158737Sambrisko mfi_aen_register(sc, seq, class_locale.word); 1059159806Sps free(log_state, M_MFIBUF); 1060158737Sambrisko 1061158737Sambrisko return 0; 1062158737Sambrisko} 1063158737Sambrisko 1064233711Sambriskoint 1065159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm) 1066159811Sps{ 1067159811Sps 1068159811Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1069159811Sps cm->cm_complete = NULL; 1070159811Sps 1071170284Sambrisko 1072170284Sambrisko /* 1073170284Sambrisko * MegaCli can issue a DCMD of 0. In this case do nothing 1074170284Sambrisko * and return 0 to it as status 1075170284Sambrisko */ 1076170284Sambrisko if (cm->cm_frame->dcmd.opcode == 0) { 1077170284Sambrisko cm->cm_frame->header.cmd_status = MFI_STAT_OK; 1078170284Sambrisko cm->cm_error = 0; 1079170284Sambrisko return (cm->cm_error); 1080170284Sambrisko } 1081159811Sps mfi_enqueue_ready(cm); 1082159811Sps mfi_startio(sc); 1083170284Sambrisko if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0) 1084170284Sambrisko msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0); 1085170284Sambrisko return (cm->cm_error); 1086159811Sps} 1087159811Sps 1088157114Sscottlvoid 1089157114Sscottlmfi_free(struct mfi_softc *sc) 1090157114Sscottl{ 1091157114Sscottl struct mfi_command *cm; 1092157114Sscottl int i; 1093157114Sscottl 1094162619Sscottl callout_drain(&sc->mfi_watchdog_callout); 1095162619Sscottl 1096157114Sscottl if (sc->mfi_cdev != NULL) 1097157114Sscottl destroy_dev(sc->mfi_cdev); 1098157114Sscottl 1099157114Sscottl if (sc->mfi_total_cmds != 0) { 1100157114Sscottl for (i = 0; i < sc->mfi_total_cmds; i++) { 1101157114Sscottl cm = &sc->mfi_commands[i]; 1102157114Sscottl bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap); 1103157114Sscottl } 1104157114Sscottl free(sc->mfi_commands, M_MFIBUF); 1105157114Sscottl } 1106157114Sscottl 1107157114Sscottl if (sc->mfi_intr) 1108157114Sscottl bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr); 1109157114Sscottl if (sc->mfi_irq != NULL) 1110157114Sscottl bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid, 1111157114Sscottl sc->mfi_irq); 1112157114Sscottl 1113157114Sscottl if (sc->mfi_sense_busaddr != 0) 1114157114Sscottl bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap); 1115157114Sscottl if (sc->mfi_sense != NULL) 1116157114Sscottl bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense, 1117157114Sscottl sc->mfi_sense_dmamap); 1118157114Sscottl if (sc->mfi_sense_dmat != NULL) 1119157114Sscottl bus_dma_tag_destroy(sc->mfi_sense_dmat); 1120157114Sscottl 1121157114Sscottl if (sc->mfi_frames_busaddr != 0) 1122157114Sscottl bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap); 1123157114Sscottl if (sc->mfi_frames != NULL) 1124157114Sscottl bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames, 1125157114Sscottl sc->mfi_frames_dmamap); 1126157114Sscottl if (sc->mfi_frames_dmat != NULL) 1127157114Sscottl bus_dma_tag_destroy(sc->mfi_frames_dmat); 1128157114Sscottl 1129157114Sscottl if (sc->mfi_comms_busaddr != 0) 1130157114Sscottl bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap); 1131157114Sscottl if (sc->mfi_comms != NULL) 1132157114Sscottl bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms, 1133157114Sscottl sc->mfi_comms_dmamap); 1134157114Sscottl if (sc->mfi_comms_dmat != NULL) 1135157114Sscottl bus_dma_tag_destroy(sc->mfi_comms_dmat); 1136157114Sscottl 1137233711Sambrisko /* ThunderBolt contiguous memory free here */ 1138233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 1139233711Sambrisko if (sc->mfi_tb_busaddr != 0) 1140233711Sambrisko bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap); 1141233711Sambrisko if (sc->request_message_pool != NULL) 1142233711Sambrisko bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool, 1143233711Sambrisko sc->mfi_tb_dmamap); 1144233711Sambrisko if (sc->mfi_tb_dmat != NULL) 1145233711Sambrisko bus_dma_tag_destroy(sc->mfi_tb_dmat); 1146233711Sambrisko 1147233711Sambrisko /* Version buffer memory free */ 1148233711Sambrisko /* Start LSIP200113393 */ 1149233711Sambrisko if (sc->verbuf_h_busaddr != 0) 1150233711Sambrisko bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap); 1151233711Sambrisko if (sc->verbuf != NULL) 1152233711Sambrisko bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf, 1153233711Sambrisko sc->verbuf_h_dmamap); 1154233711Sambrisko if (sc->verbuf_h_dmat != NULL) 1155233711Sambrisko bus_dma_tag_destroy(sc->verbuf_h_dmat); 1156233711Sambrisko 1157233711Sambrisko /* End LSIP200113393 */ 1158233711Sambrisko /* ThunderBolt INIT packet memory Free */ 1159233711Sambrisko if (sc->mfi_tb_init_busaddr != 0) 1160233711Sambrisko bus_dmamap_unload(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap); 1161233711Sambrisko if (sc->mfi_tb_init != NULL) 1162233711Sambrisko bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init, 1163233711Sambrisko sc->mfi_tb_init_dmamap); 1164233711Sambrisko if (sc->mfi_tb_init_dmat != NULL) 1165233711Sambrisko bus_dma_tag_destroy(sc->mfi_tb_init_dmat); 1166233711Sambrisko 1167233711Sambrisko /* ThunderBolt IOC Init Desc memory free here */ 1168233711Sambrisko if (sc->mfi_tb_ioc_init_busaddr != 0) 1169233711Sambrisko bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat, 1170233711Sambrisko sc->mfi_tb_ioc_init_dmamap); 1171233711Sambrisko if (sc->mfi_tb_ioc_init_desc != NULL) 1172233711Sambrisko bus_dmamem_free(sc->mfi_tb_ioc_init_dmat, 1173233711Sambrisko sc->mfi_tb_ioc_init_desc, 1174233711Sambrisko sc->mfi_tb_ioc_init_dmamap); 1175233711Sambrisko if (sc->mfi_tb_ioc_init_dmat != NULL) 1176233711Sambrisko bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat); 1177233711Sambrisko for (int i = 0; i < sc->mfi_max_fw_cmds; i++) { 1178233711Sambrisko if (sc->mfi_cmd_pool_tbolt != NULL) { 1179233711Sambrisko if (sc->mfi_cmd_pool_tbolt[i] != NULL) { 1180233711Sambrisko free(sc->mfi_cmd_pool_tbolt[i], 1181233711Sambrisko M_MFIBUF); 1182233711Sambrisko sc->mfi_cmd_pool_tbolt[i] = NULL; 1183233711Sambrisko } 1184233711Sambrisko } 1185233711Sambrisko } 1186233711Sambrisko if (sc->mfi_cmd_pool_tbolt != NULL) { 1187233711Sambrisko free(sc->mfi_cmd_pool_tbolt, M_MFIBUF); 1188233711Sambrisko sc->mfi_cmd_pool_tbolt = NULL; 1189233711Sambrisko } 1190233711Sambrisko if (sc->request_desc_pool != NULL) { 1191233711Sambrisko free(sc->request_desc_pool, M_MFIBUF); 1192233711Sambrisko sc->request_desc_pool = NULL; 1193233711Sambrisko } 1194233711Sambrisko } 1195157114Sscottl if (sc->mfi_buffer_dmat != NULL) 1196157114Sscottl bus_dma_tag_destroy(sc->mfi_buffer_dmat); 1197157114Sscottl if (sc->mfi_parent_dmat != NULL) 1198157114Sscottl bus_dma_tag_destroy(sc->mfi_parent_dmat); 1199157114Sscottl 1200171821Sjhb if (mtx_initialized(&sc->mfi_io_lock)) { 1201157114Sscottl mtx_destroy(&sc->mfi_io_lock); 1202171821Sjhb sx_destroy(&sc->mfi_config_lock); 1203171821Sjhb } 1204157114Sscottl 1205157114Sscottl return; 1206157114Sscottl} 1207157114Sscottl 1208157114Sscottlstatic void 1209157114Sscottlmfi_startup(void *arg) 1210157114Sscottl{ 1211157114Sscottl struct mfi_softc *sc; 1212157114Sscottl 1213157114Sscottl sc = (struct mfi_softc *)arg; 1214157114Sscottl 1215157114Sscottl config_intrhook_disestablish(&sc->mfi_ich); 1216157114Sscottl 1217171980Sscottl sc->mfi_enable_intr(sc); 1218171821Sjhb sx_xlock(&sc->mfi_config_lock); 1219163398Sscottl mtx_lock(&sc->mfi_io_lock); 1220159811Sps mfi_ldprobe(sc); 1221233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) 1222233711Sambrisko mfi_syspdprobe(sc); 1223163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1224171821Sjhb sx_xunlock(&sc->mfi_config_lock); 1225157114Sscottl} 1226157114Sscottl 1227157114Sscottlstatic void 1228157114Sscottlmfi_intr(void *arg) 1229157114Sscottl{ 1230157114Sscottl struct mfi_softc *sc; 1231157114Sscottl struct mfi_command *cm; 1232171980Sscottl uint32_t pi, ci, context; 1233157114Sscottl 1234157114Sscottl sc = (struct mfi_softc *)arg; 1235157114Sscottl 1236171980Sscottl if (sc->mfi_check_clear_intr(sc)) 1237157114Sscottl return; 1238163398Sscottl 1239233711Sambriskorestart: 1240157114Sscottl pi = sc->mfi_comms->hw_pi; 1241157114Sscottl ci = sc->mfi_comms->hw_ci; 1242157114Sscottl mtx_lock(&sc->mfi_io_lock); 1243157114Sscottl while (ci != pi) { 1244157114Sscottl context = sc->mfi_comms->hw_reply_q[ci]; 1245170284Sambrisko if (context < sc->mfi_max_fw_cmds) { 1246170284Sambrisko cm = &sc->mfi_commands[context]; 1247170284Sambrisko mfi_remove_busy(cm); 1248170284Sambrisko cm->cm_error = 0; 1249170284Sambrisko mfi_complete(sc, cm); 1250170284Sambrisko } 1251162099Sscottl if (++ci == (sc->mfi_max_fw_cmds + 1)) { 1252157114Sscottl ci = 0; 1253157114Sscottl } 1254157114Sscottl } 1255157114Sscottl 1256157114Sscottl sc->mfi_comms->hw_ci = ci; 1257157114Sscottl 1258163398Sscottl /* Give defered I/O a chance to run */ 1259163398Sscottl if (sc->mfi_flags & MFI_FLAGS_QFRZN) 1260163398Sscottl sc->mfi_flags &= ~MFI_FLAGS_QFRZN; 1261163398Sscottl mfi_startio(sc); 1262163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1263163398Sscottl 1264233711Sambrisko /* 1265233711Sambrisko * Dummy read to flush the bus; this ensures that the indexes are up 1266233711Sambrisko * to date. Restart processing if more commands have come it. 1267233711Sambrisko */ 1268233711Sambrisko (void)sc->mfi_read_fw_status(sc); 1269233711Sambrisko if (pi != sc->mfi_comms->hw_pi) 1270233711Sambrisko goto restart; 1271233711Sambrisko 1272157114Sscottl return; 1273157114Sscottl} 1274157114Sscottl 1275157114Sscottlint 1276157114Sscottlmfi_shutdown(struct mfi_softc *sc) 1277157114Sscottl{ 1278157114Sscottl struct mfi_dcmd_frame *dcmd; 1279157114Sscottl struct mfi_command *cm; 1280157114Sscottl int error; 1281157114Sscottl 1282159806Sps mtx_lock(&sc->mfi_io_lock); 1283159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0); 1284163398Sscottl if (error) { 1285163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1286159806Sps return (error); 1287163398Sscottl } 1288157114Sscottl 1289158737Sambrisko if (sc->mfi_aen_cm != NULL) 1290158737Sambrisko mfi_abort(sc, sc->mfi_aen_cm); 1291157114Sscottl 1292235014Sambrisko if (sc->mfi_map_sync_cm != NULL) 1293235014Sambrisko mfi_abort(sc, sc->mfi_map_sync_cm); 1294233711Sambrisko 1295157114Sscottl dcmd = &cm->cm_frame->dcmd; 1296157114Sscottl dcmd->header.flags = MFI_FRAME_DIR_NONE; 1297164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 1298164375Sscottl cm->cm_data = NULL; 1299157114Sscottl 1300164375Sscottl if ((error = mfi_mapcmd(sc, cm)) != 0) { 1301157114Sscottl device_printf(sc->mfi_dev, "Failed to shutdown controller\n"); 1302157114Sscottl } 1303157114Sscottl 1304159812Sps mfi_release_command(cm); 1305163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1306157114Sscottl return (error); 1307157114Sscottl} 1308157114Sscottl 1309157114Sscottlstatic void 1310233711Sambriskomfi_syspdprobe(struct mfi_softc *sc) 1311233711Sambrisko{ 1312233711Sambrisko struct mfi_frame_header *hdr; 1313233711Sambrisko struct mfi_command *cm = NULL; 1314233711Sambrisko struct mfi_pd_list *pdlist = NULL; 1315233711Sambrisko struct mfi_system_pd *syspd, *tmp; 1316233711Sambrisko int error, i, found; 1317233711Sambrisko 1318233711Sambrisko sx_assert(&sc->mfi_config_lock, SA_XLOCKED); 1319233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1320233711Sambrisko /* Add SYSTEM PD's */ 1321233711Sambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY, 1322233711Sambrisko (void **)&pdlist, sizeof(*pdlist)); 1323235016Sambrisko if (error) { 1324233711Sambrisko device_printf(sc->mfi_dev, 1325233711Sambrisko "Error while forming SYSTEM PD list\n"); 1326233711Sambrisko goto out; 1327233711Sambrisko } 1328233711Sambrisko 1329233711Sambrisko cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1330233711Sambrisko cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST; 1331233711Sambrisko cm->cm_frame->dcmd.mbox[1] = 0; 1332233711Sambrisko if (mfi_mapcmd(sc, cm) != 0) { 1333233711Sambrisko device_printf(sc->mfi_dev, 1334233711Sambrisko "Failed to get syspd device listing\n"); 1335233711Sambrisko goto out; 1336233711Sambrisko } 1337233711Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap, 1338233711Sambrisko BUS_DMASYNC_POSTREAD); 1339233711Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1340233711Sambrisko hdr = &cm->cm_frame->header; 1341233711Sambrisko if (hdr->cmd_status != MFI_STAT_OK) { 1342233711Sambrisko device_printf(sc->mfi_dev, 1343233711Sambrisko "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status); 1344233711Sambrisko goto out; 1345233711Sambrisko } 1346233711Sambrisko /* Get each PD and add it to the system */ 1347233711Sambrisko for (i = 0; i < pdlist->count; i++) { 1348233711Sambrisko if (pdlist->addr[i].device_id == 1349233711Sambrisko pdlist->addr[i].encl_device_id) 1350233711Sambrisko continue; 1351233711Sambrisko found = 0; 1352233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { 1353233711Sambrisko if (syspd->pd_id == pdlist->addr[i].device_id) 1354233711Sambrisko found = 1; 1355233711Sambrisko } 1356233711Sambrisko if (found == 0) 1357233711Sambrisko mfi_add_sys_pd(sc, pdlist->addr[i].device_id); 1358233711Sambrisko } 1359233711Sambrisko /* Delete SYSPD's whose state has been changed */ 1360233711Sambrisko TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) { 1361233711Sambrisko found = 0; 1362233711Sambrisko for (i = 0; i < pdlist->count; i++) { 1363233711Sambrisko if (syspd->pd_id == pdlist->addr[i].device_id) 1364233711Sambrisko found = 1; 1365233711Sambrisko } 1366233711Sambrisko if (found == 0) { 1367233711Sambrisko printf("DELETE\n"); 1368233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1369233711Sambrisko mtx_lock(&Giant); 1370233711Sambrisko device_delete_child(sc->mfi_dev, syspd->pd_dev); 1371233711Sambrisko mtx_unlock(&Giant); 1372233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1373233711Sambrisko } 1374233711Sambrisko } 1375233711Sambriskoout: 1376233711Sambrisko if (pdlist) 1377233711Sambrisko free(pdlist, M_MFIBUF); 1378233711Sambrisko if (cm) 1379233711Sambrisko mfi_release_command(cm); 1380233711Sambrisko 1381233711Sambrisko return; 1382233711Sambrisko} 1383233711Sambrisko 1384233711Sambriskostatic void 1385159811Spsmfi_ldprobe(struct mfi_softc *sc) 1386157114Sscottl{ 1387159811Sps struct mfi_frame_header *hdr; 1388159811Sps struct mfi_command *cm = NULL; 1389159811Sps struct mfi_ld_list *list = NULL; 1390171821Sjhb struct mfi_disk *ld; 1391159811Sps int error, i; 1392157114Sscottl 1393171821Sjhb sx_assert(&sc->mfi_config_lock, SA_XLOCKED); 1394163398Sscottl mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1395163398Sscottl 1396159811Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST, 1397159811Sps (void **)&list, sizeof(*list)); 1398159811Sps if (error) 1399159811Sps goto out; 1400159811Sps 1401159811Sps cm->cm_flags = MFI_CMD_DATAIN; 1402159811Sps if (mfi_wait_command(sc, cm) != 0) { 1403159811Sps device_printf(sc->mfi_dev, "Failed to get device listing\n"); 1404159811Sps goto out; 1405157114Sscottl } 1406157114Sscottl 1407157114Sscottl hdr = &cm->cm_frame->header; 1408159811Sps if (hdr->cmd_status != MFI_STAT_OK) { 1409159811Sps device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n", 1410159811Sps hdr->cmd_status); 1411159811Sps goto out; 1412157114Sscottl } 1413157114Sscottl 1414171821Sjhb for (i = 0; i < list->ld_count; i++) { 1415171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 1416171821Sjhb if (ld->ld_id == list->ld_list[i].ld.v.target_id) 1417171821Sjhb goto skip_add; 1418171821Sjhb } 1419163398Sscottl mfi_add_ld(sc, list->ld_list[i].ld.v.target_id); 1420171821Sjhb skip_add:; 1421171821Sjhb } 1422159811Spsout: 1423159811Sps if (list) 1424159811Sps free(list, M_MFIBUF); 1425159811Sps if (cm) 1426157114Sscottl mfi_release_command(cm); 1427163398Sscottl 1428159811Sps return; 1429157114Sscottl} 1430157114Sscottl 1431180038Sjhb/* 1432180038Sjhb * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If 1433180038Sjhb * the bits in 24-31 are all set, then it is the number of seconds since 1434180038Sjhb * boot. 1435180038Sjhb */ 1436180038Sjhbstatic const char * 1437180038Sjhbformat_timestamp(uint32_t timestamp) 1438158737Sambrisko{ 1439180038Sjhb static char buffer[32]; 1440180038Sjhb 1441180038Sjhb if ((timestamp & 0xff000000) == 0xff000000) 1442180038Sjhb snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & 1443180038Sjhb 0x00ffffff); 1444180038Sjhb else 1445180038Sjhb snprintf(buffer, sizeof(buffer), "%us", timestamp); 1446180038Sjhb return (buffer); 1447180038Sjhb} 1448180038Sjhb 1449180038Sjhbstatic const char * 1450180038Sjhbformat_class(int8_t class) 1451180038Sjhb{ 1452180038Sjhb static char buffer[6]; 1453180038Sjhb 1454180038Sjhb switch (class) { 1455180038Sjhb case MFI_EVT_CLASS_DEBUG: 1456180038Sjhb return ("debug"); 1457180038Sjhb case MFI_EVT_CLASS_PROGRESS: 1458180038Sjhb return ("progress"); 1459180038Sjhb case MFI_EVT_CLASS_INFO: 1460180038Sjhb return ("info"); 1461180038Sjhb case MFI_EVT_CLASS_WARNING: 1462180038Sjhb return ("WARN"); 1463180038Sjhb case MFI_EVT_CLASS_CRITICAL: 1464180038Sjhb return ("CRIT"); 1465180038Sjhb case MFI_EVT_CLASS_FATAL: 1466180038Sjhb return ("FATAL"); 1467180038Sjhb case MFI_EVT_CLASS_DEAD: 1468180038Sjhb return ("DEAD"); 1469158737Sambrisko default: 1470180038Sjhb snprintf(buffer, sizeof(buffer), "%d", class); 1471180038Sjhb return (buffer); 1472158737Sambrisko } 1473158737Sambrisko} 1474158737Sambrisko 1475180038Sjhbstatic void 1476180038Sjhbmfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) 1477180038Sjhb{ 1478233711Sambrisko struct mfi_system_pd *syspd = NULL; 1479180038Sjhb 1480200238Sjkim device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq, 1481222589Semaste format_timestamp(detail->time), detail->evt_class.members.locale, 1482233711Sambrisko format_class(detail->evt_class.members.evt_class), 1483233711Sambrisko detail->description); 1484233711Sambrisko 1485233711Sambrisko /* Don't act on old AEN's or while shutting down */ 1486233711Sambrisko if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching) 1487233711Sambrisko return; 1488233711Sambrisko 1489233711Sambrisko switch (detail->arg_type) { 1490233711Sambrisko case MR_EVT_ARGS_NONE: 1491233711Sambrisko if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) { 1492233711Sambrisko device_printf(sc->mfi_dev, "HostBus scan raised\n"); 1493233711Sambrisko if (mfi_detect_jbod_change) { 1494233711Sambrisko /* 1495233711Sambrisko * Probe for new SYSPD's and Delete 1496233711Sambrisko * invalid SYSPD's 1497233711Sambrisko */ 1498233711Sambrisko sx_xlock(&sc->mfi_config_lock); 1499233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1500233711Sambrisko mfi_syspdprobe(sc); 1501233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1502233711Sambrisko sx_xunlock(&sc->mfi_config_lock); 1503233711Sambrisko } 1504233711Sambrisko } 1505233711Sambrisko break; 1506233711Sambrisko case MR_EVT_ARGS_LD_STATE: 1507233711Sambrisko /* During load time driver reads all the events starting 1508233711Sambrisko * from the one that has been logged after shutdown. Avoid 1509233711Sambrisko * these old events. 1510233711Sambrisko */ 1511233711Sambrisko if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) { 1512233711Sambrisko /* Remove the LD */ 1513233711Sambrisko struct mfi_disk *ld; 1514233711Sambrisko TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 1515233711Sambrisko if (ld->ld_id == 1516233711Sambrisko detail->args.ld_state.ld.target_id) 1517233711Sambrisko break; 1518233711Sambrisko } 1519233711Sambrisko /* 1520233711Sambrisko Fix: for kernel panics when SSCD is removed 1521233711Sambrisko KASSERT(ld != NULL, ("volume dissappeared")); 1522233711Sambrisko */ 1523233711Sambrisko if (ld != NULL) { 1524233711Sambrisko mtx_lock(&Giant); 1525233711Sambrisko device_delete_child(sc->mfi_dev, ld->ld_dev); 1526233711Sambrisko mtx_unlock(&Giant); 1527233711Sambrisko } 1528233711Sambrisko } 1529233711Sambrisko break; 1530233711Sambrisko case MR_EVT_ARGS_PD: 1531233711Sambrisko if (detail->code == MR_EVT_PD_REMOVED) { 1532233711Sambrisko if (mfi_detect_jbod_change) { 1533233711Sambrisko /* 1534233711Sambrisko * If the removed device is a SYSPD then 1535233711Sambrisko * delete it 1536233711Sambrisko */ 1537233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, 1538233711Sambrisko pd_link) { 1539233711Sambrisko if (syspd->pd_id == 1540233711Sambrisko detail->args.pd.device_id) { 1541233711Sambrisko mtx_lock(&Giant); 1542233711Sambrisko device_delete_child( 1543233711Sambrisko sc->mfi_dev, 1544233711Sambrisko syspd->pd_dev); 1545233711Sambrisko mtx_unlock(&Giant); 1546233711Sambrisko break; 1547233711Sambrisko } 1548233711Sambrisko } 1549233711Sambrisko } 1550233711Sambrisko } 1551233711Sambrisko if (detail->code == MR_EVT_PD_INSERTED) { 1552233711Sambrisko if (mfi_detect_jbod_change) { 1553233711Sambrisko /* Probe for new SYSPD's */ 1554233711Sambrisko sx_xlock(&sc->mfi_config_lock); 1555233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1556233711Sambrisko mfi_syspdprobe(sc); 1557233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1558233711Sambrisko sx_xunlock(&sc->mfi_config_lock); 1559233711Sambrisko } 1560233711Sambrisko } 1561233711Sambrisko break; 1562233711Sambrisko } 1563180038Sjhb} 1564180038Sjhb 1565233711Sambriskostatic void 1566233711Sambriskomfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) 1567233711Sambrisko{ 1568233711Sambrisko struct mfi_evt_queue_elm *elm; 1569233711Sambrisko 1570233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1571233711Sambrisko elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO); 1572233711Sambrisko if (elm == NULL) 1573233711Sambrisko return; 1574233711Sambrisko memcpy(&elm->detail, detail, sizeof(*detail)); 1575233711Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link); 1576233711Sambrisko taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task); 1577233711Sambrisko} 1578233711Sambrisko 1579233711Sambriskostatic void 1580233711Sambriskomfi_handle_evt(void *context, int pending) 1581233711Sambrisko{ 1582233711Sambrisko TAILQ_HEAD(,mfi_evt_queue_elm) queue; 1583233711Sambrisko struct mfi_softc *sc; 1584233711Sambrisko struct mfi_evt_queue_elm *elm; 1585233711Sambrisko 1586233711Sambrisko sc = context; 1587233711Sambrisko TAILQ_INIT(&queue); 1588233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1589233711Sambrisko TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link); 1590233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1591233711Sambrisko while ((elm = TAILQ_FIRST(&queue)) != NULL) { 1592233711Sambrisko TAILQ_REMOVE(&queue, elm, link); 1593233711Sambrisko mfi_decode_evt(sc, &elm->detail); 1594233711Sambrisko free(elm, M_MFIBUF); 1595233711Sambrisko } 1596233711Sambrisko} 1597233711Sambrisko 1598157114Sscottlstatic int 1599158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale) 1600158737Sambrisko{ 1601158737Sambrisko struct mfi_command *cm; 1602158737Sambrisko struct mfi_dcmd_frame *dcmd; 1603158737Sambrisko union mfi_evt current_aen, prior_aen; 1604159806Sps struct mfi_evt_detail *ed = NULL; 1605163398Sscottl int error = 0; 1606158737Sambrisko 1607158737Sambrisko current_aen.word = locale; 1608158737Sambrisko if (sc->mfi_aen_cm != NULL) { 1609158737Sambrisko prior_aen.word = 1610158737Sambrisko ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1]; 1611222589Semaste if (prior_aen.members.evt_class <= current_aen.members.evt_class && 1612158737Sambrisko !((prior_aen.members.locale & current_aen.members.locale) 1613158737Sambrisko ^current_aen.members.locale)) { 1614158737Sambrisko return (0); 1615158737Sambrisko } else { 1616158737Sambrisko prior_aen.members.locale |= current_aen.members.locale; 1617222589Semaste if (prior_aen.members.evt_class 1618222589Semaste < current_aen.members.evt_class) 1619222589Semaste current_aen.members.evt_class = 1620222589Semaste prior_aen.members.evt_class; 1621233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1622158737Sambrisko mfi_abort(sc, sc->mfi_aen_cm); 1623233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1624158737Sambrisko } 1625158737Sambrisko } 1626158737Sambrisko 1627233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1628159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT, 1629159806Sps (void **)&ed, sizeof(*ed)); 1630233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1631163398Sscottl if (error) { 1632163398Sscottl goto out; 1633163398Sscottl } 1634158737Sambrisko 1635158737Sambrisko dcmd = &cm->cm_frame->dcmd; 1636158737Sambrisko ((uint32_t *)&dcmd->mbox)[0] = seq; 1637158737Sambrisko ((uint32_t *)&dcmd->mbox)[1] = locale; 1638158737Sambrisko cm->cm_flags = MFI_CMD_DATAIN; 1639158737Sambrisko cm->cm_complete = mfi_aen_complete; 1640158737Sambrisko 1641233711Sambrisko sc->last_seq_num = seq; 1642158737Sambrisko sc->mfi_aen_cm = cm; 1643158737Sambrisko 1644233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1645158737Sambrisko mfi_enqueue_ready(cm); 1646158737Sambrisko mfi_startio(sc); 1647233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1648158737Sambrisko 1649163398Sscottlout: 1650163398Sscottl return (error); 1651158737Sambrisko} 1652158737Sambrisko 1653158737Sambriskostatic void 1654158737Sambriskomfi_aen_complete(struct mfi_command *cm) 1655158737Sambrisko{ 1656158737Sambrisko struct mfi_frame_header *hdr; 1657158737Sambrisko struct mfi_softc *sc; 1658158737Sambrisko struct mfi_evt_detail *detail; 1659163398Sscottl struct mfi_aen *mfi_aen_entry, *tmp; 1660158737Sambrisko int seq = 0, aborted = 0; 1661158737Sambrisko 1662158737Sambrisko sc = cm->cm_sc; 1663233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1664233711Sambrisko 1665158737Sambrisko hdr = &cm->cm_frame->header; 1666158737Sambrisko 1667158737Sambrisko if (sc->mfi_aen_cm == NULL) 1668158737Sambrisko return; 1669158737Sambrisko 1670235014Sambrisko if (sc->cm_aen_abort || 1671224039Sjhb hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 1672235014Sambrisko sc->cm_aen_abort = 0; 1673158737Sambrisko aborted = 1; 1674158737Sambrisko } else { 1675158737Sambrisko sc->mfi_aen_triggered = 1; 1676163398Sscottl if (sc->mfi_poll_waiting) { 1677163398Sscottl sc->mfi_poll_waiting = 0; 1678158737Sambrisko selwakeup(&sc->mfi_select); 1679163398Sscottl } 1680158737Sambrisko detail = cm->cm_data; 1681233711Sambrisko mfi_queue_evt(sc, detail); 1682158737Sambrisko seq = detail->seq + 1; 1683233711Sambrisko TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, 1684233711Sambrisko tmp) { 1685158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 1686158737Sambrisko aen_link); 1687163398Sscottl PROC_LOCK(mfi_aen_entry->p); 1688225617Skmacy kern_psignal(mfi_aen_entry->p, SIGIO); 1689163398Sscottl PROC_UNLOCK(mfi_aen_entry->p); 1690158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 1691158737Sambrisko } 1692158737Sambrisko } 1693158737Sambrisko 1694158737Sambrisko free(cm->cm_data, M_MFIBUF); 1695158737Sambrisko sc->mfi_aen_cm = NULL; 1696158737Sambrisko wakeup(&sc->mfi_aen_cm); 1697158737Sambrisko mfi_release_command(cm); 1698158737Sambrisko 1699158737Sambrisko /* set it up again so the driver can catch more events */ 1700158737Sambrisko if (!aborted) { 1701233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1702158737Sambrisko mfi_aen_setup(sc, seq); 1703233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1704158737Sambrisko } 1705158737Sambrisko} 1706158737Sambrisko 1707180037Sjhb#define MAX_EVENTS 15 1708180037Sjhb 1709158737Sambriskostatic int 1710180037Sjhbmfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) 1711158737Sambrisko{ 1712158737Sambrisko struct mfi_command *cm; 1713158737Sambrisko struct mfi_dcmd_frame *dcmd; 1714162118Sambrisko struct mfi_evt_list *el; 1715180037Sjhb union mfi_evt class_locale; 1716180037Sjhb int error, i, seq, size; 1717158737Sambrisko 1718180037Sjhb class_locale.members.reserved = 0; 1719180037Sjhb class_locale.members.locale = mfi_event_locale; 1720222589Semaste class_locale.members.evt_class = mfi_event_class; 1721158737Sambrisko 1722162118Sambrisko size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) 1723162118Sambrisko * (MAX_EVENTS - 1); 1724162118Sambrisko el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO); 1725180037Sjhb if (el == NULL) 1726158737Sambrisko return (ENOMEM); 1727158737Sambrisko 1728180037Sjhb for (seq = start_seq;;) { 1729233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1730180037Sjhb if ((cm = mfi_dequeue_free(sc)) == NULL) { 1731180037Sjhb free(el, M_MFIBUF); 1732233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1733180037Sjhb return (EBUSY); 1734180037Sjhb } 1735233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1736158737Sambrisko 1737180037Sjhb dcmd = &cm->cm_frame->dcmd; 1738180037Sjhb bzero(dcmd->mbox, MFI_MBOX_SIZE); 1739180037Sjhb dcmd->header.cmd = MFI_CMD_DCMD; 1740180037Sjhb dcmd->header.timeout = 0; 1741180037Sjhb dcmd->header.data_len = size; 1742180037Sjhb dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET; 1743180037Sjhb ((uint32_t *)&dcmd->mbox)[0] = seq; 1744180037Sjhb ((uint32_t *)&dcmd->mbox)[1] = class_locale.word; 1745180037Sjhb cm->cm_sg = &dcmd->sgl; 1746180037Sjhb cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 1747180037Sjhb cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1748180037Sjhb cm->cm_data = el; 1749180037Sjhb cm->cm_len = size; 1750180037Sjhb 1751233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1752180037Sjhb if ((error = mfi_mapcmd(sc, cm)) != 0) { 1753180037Sjhb device_printf(sc->mfi_dev, 1754180037Sjhb "Failed to get controller entries\n"); 1755180037Sjhb mfi_release_command(cm); 1756233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1757180037Sjhb break; 1758180037Sjhb } 1759180037Sjhb 1760233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1761180037Sjhb bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1762180037Sjhb BUS_DMASYNC_POSTREAD); 1763180037Sjhb bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1764180037Sjhb 1765180037Sjhb if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) { 1766233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1767180037Sjhb mfi_release_command(cm); 1768233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1769180037Sjhb break; 1770180037Sjhb } 1771180037Sjhb if (dcmd->header.cmd_status != MFI_STAT_OK) { 1772180037Sjhb device_printf(sc->mfi_dev, 1773180037Sjhb "Error %d fetching controller entries\n", 1774180037Sjhb dcmd->header.cmd_status); 1775233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1776180037Sjhb mfi_release_command(cm); 1777233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1778180037Sjhb break; 1779180037Sjhb } 1780233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1781158737Sambrisko mfi_release_command(cm); 1782233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1783158737Sambrisko 1784162473Sambrisko for (i = 0; i < el->count; i++) { 1785180037Sjhb /* 1786180037Sjhb * If this event is newer than 'stop_seq' then 1787180037Sjhb * break out of the loop. Note that the log 1788180037Sjhb * is a circular buffer so we have to handle 1789180037Sjhb * the case that our stop point is earlier in 1790180037Sjhb * the buffer than our start point. 1791180037Sjhb */ 1792180037Sjhb if (el->event[i].seq >= stop_seq) { 1793180037Sjhb if (start_seq <= stop_seq) 1794180037Sjhb break; 1795180037Sjhb else if (el->event[i].seq < start_seq) 1796180037Sjhb break; 1797180037Sjhb } 1798233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1799233711Sambrisko mfi_queue_evt(sc, &el->event[i]); 1800233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1801162473Sambrisko } 1802180037Sjhb seq = el->event[el->count - 1].seq + 1; 1803162118Sambrisko } 1804158737Sambrisko 1805180037Sjhb free(el, M_MFIBUF); 1806158737Sambrisko return (0); 1807158737Sambrisko} 1808158737Sambrisko 1809158737Sambriskostatic int 1810159811Spsmfi_add_ld(struct mfi_softc *sc, int id) 1811157114Sscottl{ 1812157114Sscottl struct mfi_command *cm; 1813159811Sps struct mfi_dcmd_frame *dcmd = NULL; 1814159811Sps struct mfi_ld_info *ld_info = NULL; 1815159811Sps int error; 1816157114Sscottl 1817159811Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1818159811Sps 1819159811Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO, 1820159811Sps (void **)&ld_info, sizeof(*ld_info)); 1821159811Sps if (error) { 1822159811Sps device_printf(sc->mfi_dev, 1823159811Sps "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error); 1824159811Sps if (ld_info) 1825159811Sps free(ld_info, M_MFIBUF); 1826159811Sps return (error); 1827157624Sscottl } 1828159811Sps cm->cm_flags = MFI_CMD_DATAIN; 1829159811Sps dcmd = &cm->cm_frame->dcmd; 1830159811Sps dcmd->mbox[0] = id; 1831160052Sambrisko if (mfi_wait_command(sc, cm) != 0) { 1832160052Sambrisko device_printf(sc->mfi_dev, 1833160052Sambrisko "Failed to get logical drive: %d\n", id); 1834160052Sambrisko free(ld_info, M_MFIBUF); 1835160052Sambrisko return (0); 1836160052Sambrisko } 1837233711Sambrisko if (ld_info->ld_config.params.isSSCD != 1) 1838233711Sambrisko mfi_add_ld_complete(cm); 1839233711Sambrisko else { 1840233711Sambrisko mfi_release_command(cm); 1841233711Sambrisko if (ld_info) /* SSCD drives ld_info free here */ 1842233711Sambrisko free(ld_info, M_MFIBUF); 1843233711Sambrisko } 1844157114Sscottl return (0); 1845157114Sscottl} 1846157114Sscottl 1847157114Sscottlstatic void 1848159811Spsmfi_add_ld_complete(struct mfi_command *cm) 1849157114Sscottl{ 1850157114Sscottl struct mfi_frame_header *hdr; 1851159811Sps struct mfi_ld_info *ld_info; 1852157114Sscottl struct mfi_softc *sc; 1853159811Sps device_t child; 1854157114Sscottl 1855157114Sscottl sc = cm->cm_sc; 1856157114Sscottl hdr = &cm->cm_frame->header; 1857159811Sps ld_info = cm->cm_private; 1858157114Sscottl 1859159811Sps if (hdr->cmd_status != MFI_STAT_OK) { 1860159811Sps free(ld_info, M_MFIBUF); 1861157114Sscottl mfi_release_command(cm); 1862157114Sscottl return; 1863157114Sscottl } 1864157114Sscottl mfi_release_command(cm); 1865157114Sscottl 1866169611Sscottl mtx_unlock(&sc->mfi_io_lock); 1867196403Sjhb mtx_lock(&Giant); 1868157114Sscottl if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) { 1869157114Sscottl device_printf(sc->mfi_dev, "Failed to add logical disk\n"); 1870159811Sps free(ld_info, M_MFIBUF); 1871196403Sjhb mtx_unlock(&Giant); 1872169611Sscottl mtx_lock(&sc->mfi_io_lock); 1873159811Sps return; 1874157114Sscottl } 1875157114Sscottl 1876169451Sscottl device_set_ivars(child, ld_info); 1877157114Sscottl device_set_desc(child, "MFI Logical Disk"); 1878157114Sscottl bus_generic_attach(sc->mfi_dev); 1879196403Sjhb mtx_unlock(&Giant); 1880157114Sscottl mtx_lock(&sc->mfi_io_lock); 1881157114Sscottl} 1882163399Sscottl 1883233711Sambriskostatic int mfi_add_sys_pd(struct mfi_softc *sc, int id) 1884233711Sambrisko{ 1885233711Sambrisko struct mfi_command *cm; 1886233711Sambrisko struct mfi_dcmd_frame *dcmd = NULL; 1887233711Sambrisko struct mfi_pd_info *pd_info = NULL; 1888233711Sambrisko int error; 1889233711Sambrisko 1890233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1891233711Sambrisko 1892233711Sambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO, 1893233711Sambrisko (void **)&pd_info, sizeof(*pd_info)); 1894233711Sambrisko if (error) { 1895233711Sambrisko device_printf(sc->mfi_dev, 1896233711Sambrisko "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n", 1897233711Sambrisko error); 1898233711Sambrisko if (pd_info) 1899233711Sambrisko free(pd_info, M_MFIBUF); 1900233711Sambrisko return (error); 1901233711Sambrisko } 1902233711Sambrisko cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1903233711Sambrisko dcmd = &cm->cm_frame->dcmd; 1904233711Sambrisko dcmd->mbox[0]=id; 1905233711Sambrisko dcmd->header.scsi_status = 0; 1906233711Sambrisko dcmd->header.pad0 = 0; 1907233711Sambrisko if (mfi_mapcmd(sc, cm) != 0) { 1908233711Sambrisko device_printf(sc->mfi_dev, 1909233711Sambrisko "Failed to get physical drive info %d\n", id); 1910233711Sambrisko free(pd_info, M_MFIBUF); 1911233711Sambrisko return (0); 1912233711Sambrisko } 1913233711Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1914233711Sambrisko BUS_DMASYNC_POSTREAD); 1915233711Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1916233711Sambrisko mfi_add_sys_pd_complete(cm); 1917233711Sambrisko return (0); 1918233711Sambrisko} 1919233711Sambrisko 1920233711Sambriskostatic void 1921233711Sambriskomfi_add_sys_pd_complete(struct mfi_command *cm) 1922233711Sambrisko{ 1923233711Sambrisko struct mfi_frame_header *hdr; 1924233711Sambrisko struct mfi_pd_info *pd_info; 1925233711Sambrisko struct mfi_softc *sc; 1926233711Sambrisko device_t child; 1927233711Sambrisko 1928233711Sambrisko sc = cm->cm_sc; 1929233711Sambrisko hdr = &cm->cm_frame->header; 1930233711Sambrisko pd_info = cm->cm_private; 1931233711Sambrisko 1932233711Sambrisko if (hdr->cmd_status != MFI_STAT_OK) { 1933233711Sambrisko free(pd_info, M_MFIBUF); 1934233711Sambrisko mfi_release_command(cm); 1935233711Sambrisko return; 1936233711Sambrisko } 1937233711Sambrisko if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) { 1938233711Sambrisko device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n", 1939233711Sambrisko pd_info->ref.v.device_id); 1940233711Sambrisko free(pd_info, M_MFIBUF); 1941233711Sambrisko mfi_release_command(cm); 1942233711Sambrisko return; 1943233711Sambrisko } 1944233711Sambrisko mfi_release_command(cm); 1945233711Sambrisko 1946233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1947233711Sambrisko mtx_lock(&Giant); 1948233711Sambrisko if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) { 1949233711Sambrisko device_printf(sc->mfi_dev, "Failed to add system pd\n"); 1950233711Sambrisko free(pd_info, M_MFIBUF); 1951233711Sambrisko mtx_unlock(&Giant); 1952233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1953233711Sambrisko return; 1954233711Sambrisko } 1955233711Sambrisko 1956233711Sambrisko device_set_ivars(child, pd_info); 1957233711Sambrisko device_set_desc(child, "MFI System PD"); 1958233711Sambrisko bus_generic_attach(sc->mfi_dev); 1959233711Sambrisko mtx_unlock(&Giant); 1960233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1961233711Sambrisko} 1962235016Sambrisko 1963157114Sscottlstatic struct mfi_command * 1964157114Sscottlmfi_bio_command(struct mfi_softc *sc) 1965157114Sscottl{ 1966157114Sscottl struct bio *bio; 1967233711Sambrisko struct mfi_command *cm = NULL; 1968157114Sscottl 1969233711Sambrisko /*reserving two commands to avoid starvation for IOCTL*/ 1970235016Sambrisko if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) { 1971157114Sscottl return (NULL); 1972233711Sambrisko } 1973157114Sscottl if ((bio = mfi_dequeue_bio(sc)) == NULL) { 1974157114Sscottl return (NULL); 1975157114Sscottl } 1976233711Sambrisko if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) { 1977233711Sambrisko cm = mfi_build_ldio(sc, bio); 1978233711Sambrisko } else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) { 1979233711Sambrisko cm = mfi_build_syspdio(sc, bio); 1980233711Sambrisko } 1981233711Sambrisko if (!cm) 1982233711Sambrisko mfi_enqueue_bio(sc, bio); 1983233711Sambrisko return cm; 1984233711Sambrisko} 1985233711Sambriskostatic struct mfi_command * 1986233711Sambriskomfi_build_syspdio(struct mfi_softc *sc, struct bio *bio) 1987233711Sambrisko{ 1988233711Sambrisko struct mfi_command *cm; 1989233711Sambrisko struct mfi_pass_frame *pass; 1990233711Sambrisko int flags = 0, blkcount = 0; 1991233711Sambrisko uint32_t context = 0; 1992157114Sscottl 1993233711Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 1994233711Sambrisko return (NULL); 1995233711Sambrisko 1996233711Sambrisko /* Zero out the MFI frame */ 1997233711Sambrisko context = cm->cm_frame->header.context; 1998233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 1999233711Sambrisko cm->cm_frame->header.context = context; 2000233711Sambrisko pass = &cm->cm_frame->pass; 2001233711Sambrisko bzero(pass->cdb, 16); 2002233711Sambrisko pass->header.cmd = MFI_CMD_PD_SCSI_IO; 2003233711Sambrisko switch (bio->bio_cmd & 0x03) { 2004233711Sambrisko case BIO_READ: 2005233711Sambrisko#define SCSI_READ 0x28 2006233711Sambrisko pass->cdb[0] = SCSI_READ; 2007233711Sambrisko flags = MFI_CMD_DATAIN; 2008233711Sambrisko break; 2009233711Sambrisko case BIO_WRITE: 2010233711Sambrisko#define SCSI_WRITE 0x2a 2011233711Sambrisko pass->cdb[0] = SCSI_WRITE; 2012233711Sambrisko flags = MFI_CMD_DATAOUT; 2013233711Sambrisko break; 2014233711Sambrisko default: 2015233711Sambrisko panic("Invalid bio command"); 2016233711Sambrisko } 2017233711Sambrisko 2018233711Sambrisko /* Cheat with the sector length to avoid a non-constant division */ 2019233711Sambrisko blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2020233711Sambrisko /* Fill the LBA and Transfer length in CDB */ 2021233711Sambrisko pass->cdb[2] = (bio->bio_pblkno & 0xff000000) >> 24; 2022233711Sambrisko pass->cdb[3] = (bio->bio_pblkno & 0x00ff0000) >> 16; 2023233711Sambrisko pass->cdb[4] = (bio->bio_pblkno & 0x0000ff00) >> 8; 2024233711Sambrisko pass->cdb[5] = bio->bio_pblkno & 0x000000ff; 2025233711Sambrisko pass->cdb[7] = (blkcount & 0xff00) >> 8; 2026233711Sambrisko pass->cdb[8] = (blkcount & 0x00ff); 2027233711Sambrisko pass->header.target_id = (uintptr_t)bio->bio_driver1; 2028233711Sambrisko pass->header.timeout = 0; 2029233711Sambrisko pass->header.flags = 0; 2030233711Sambrisko pass->header.scsi_status = 0; 2031233711Sambrisko pass->header.sense_len = MFI_SENSE_LEN; 2032233711Sambrisko pass->header.data_len = bio->bio_bcount; 2033233711Sambrisko pass->header.cdb_len = 10; 2034233711Sambrisko pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2035233711Sambrisko pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2036233711Sambrisko cm->cm_complete = mfi_bio_complete; 2037233711Sambrisko cm->cm_private = bio; 2038233711Sambrisko cm->cm_data = bio->bio_data; 2039233711Sambrisko cm->cm_len = bio->bio_bcount; 2040233711Sambrisko cm->cm_sg = &pass->sgl; 2041233711Sambrisko cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; 2042233711Sambrisko cm->cm_flags = flags; 2043233711Sambrisko return (cm); 2044233711Sambrisko} 2045233711Sambrisko 2046233711Sambriskostatic struct mfi_command * 2047233711Sambriskomfi_build_ldio(struct mfi_softc *sc, struct bio *bio) 2048233711Sambrisko{ 2049233711Sambrisko struct mfi_io_frame *io; 2050233711Sambrisko struct mfi_command *cm; 2051233711Sambrisko int flags, blkcount; 2052233711Sambrisko uint32_t context = 0; 2053233711Sambrisko 2054233711Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 2055233711Sambrisko return (NULL); 2056233711Sambrisko 2057233711Sambrisko /* Zero out the MFI frame */ 2058233711Sambrisko context = cm->cm_frame->header.context; 2059233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2060233711Sambrisko cm->cm_frame->header.context = context; 2061157114Sscottl io = &cm->cm_frame->io; 2062157114Sscottl switch (bio->bio_cmd & 0x03) { 2063157114Sscottl case BIO_READ: 2064157114Sscottl io->header.cmd = MFI_CMD_LD_READ; 2065157114Sscottl flags = MFI_CMD_DATAIN; 2066157114Sscottl break; 2067157114Sscottl case BIO_WRITE: 2068157114Sscottl io->header.cmd = MFI_CMD_LD_WRITE; 2069157114Sscottl flags = MFI_CMD_DATAOUT; 2070157114Sscottl break; 2071157114Sscottl default: 2072157114Sscottl panic("Invalid bio command"); 2073157114Sscottl } 2074157114Sscottl 2075157114Sscottl /* Cheat with the sector length to avoid a non-constant division */ 2076157114Sscottl blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2077157114Sscottl io->header.target_id = (uintptr_t)bio->bio_driver1; 2078157114Sscottl io->header.timeout = 0; 2079157114Sscottl io->header.flags = 0; 2080233711Sambrisko io->header.scsi_status = 0; 2081157114Sscottl io->header.sense_len = MFI_SENSE_LEN; 2082157114Sscottl io->header.data_len = blkcount; 2083233711Sambrisko io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2084233711Sambrisko io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2085157114Sscottl io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32; 2086157114Sscottl io->lba_lo = bio->bio_pblkno & 0xffffffff; 2087157114Sscottl cm->cm_complete = mfi_bio_complete; 2088157114Sscottl cm->cm_private = bio; 2089157114Sscottl cm->cm_data = bio->bio_data; 2090157114Sscottl cm->cm_len = bio->bio_bcount; 2091157114Sscottl cm->cm_sg = &io->sgl; 2092157114Sscottl cm->cm_total_frame_size = MFI_IO_FRAME_SIZE; 2093157114Sscottl cm->cm_flags = flags; 2094157114Sscottl return (cm); 2095157114Sscottl} 2096157114Sscottl 2097157114Sscottlstatic void 2098157114Sscottlmfi_bio_complete(struct mfi_command *cm) 2099157114Sscottl{ 2100157114Sscottl struct bio *bio; 2101157114Sscottl struct mfi_frame_header *hdr; 2102157114Sscottl struct mfi_softc *sc; 2103157114Sscottl 2104157114Sscottl bio = cm->cm_private; 2105157114Sscottl hdr = &cm->cm_frame->header; 2106157114Sscottl sc = cm->cm_sc; 2107157114Sscottl 2108224039Sjhb if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) { 2109157114Sscottl bio->bio_flags |= BIO_ERROR; 2110157114Sscottl bio->bio_error = EIO; 2111157114Sscottl device_printf(sc->mfi_dev, "I/O error, status= %d " 2112157114Sscottl "scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status); 2113157114Sscottl mfi_print_sense(cm->cm_sc, cm->cm_sense); 2114184897Sambrisko } else if (cm->cm_error != 0) { 2115184897Sambrisko bio->bio_flags |= BIO_ERROR; 2116157114Sscottl } 2117157114Sscottl 2118157114Sscottl mfi_release_command(cm); 2119157114Sscottl mfi_disk_complete(bio); 2120157114Sscottl} 2121157114Sscottl 2122157114Sscottlvoid 2123157114Sscottlmfi_startio(struct mfi_softc *sc) 2124157114Sscottl{ 2125157114Sscottl struct mfi_command *cm; 2126169611Sscottl struct ccb_hdr *ccbh; 2127157114Sscottl 2128157114Sscottl for (;;) { 2129157114Sscottl /* Don't bother if we're short on resources */ 2130157114Sscottl if (sc->mfi_flags & MFI_FLAGS_QFRZN) 2131157114Sscottl break; 2132157114Sscottl 2133157114Sscottl /* Try a command that has already been prepared */ 2134157114Sscottl cm = mfi_dequeue_ready(sc); 2135157114Sscottl 2136169611Sscottl if (cm == NULL) { 2137169611Sscottl if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL) 2138169611Sscottl cm = sc->mfi_cam_start(ccbh); 2139169611Sscottl } 2140169611Sscottl 2141157114Sscottl /* Nope, so look for work on the bioq */ 2142157114Sscottl if (cm == NULL) 2143157114Sscottl cm = mfi_bio_command(sc); 2144157114Sscottl 2145157114Sscottl /* No work available, so exit */ 2146157114Sscottl if (cm == NULL) 2147157114Sscottl break; 2148157114Sscottl 2149157114Sscottl /* Send the command to the controller */ 2150157114Sscottl if (mfi_mapcmd(sc, cm) != 0) { 2151157114Sscottl mfi_requeue_ready(cm); 2152157114Sscottl break; 2153157114Sscottl } 2154157114Sscottl } 2155157114Sscottl} 2156157114Sscottl 2157233711Sambriskoint 2158157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm) 2159157114Sscottl{ 2160157114Sscottl int error, polled; 2161157114Sscottl 2162163398Sscottl mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2163163398Sscottl 2164233711Sambrisko if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) { 2165157114Sscottl polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0; 2166157114Sscottl error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap, 2167157114Sscottl cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled); 2168157114Sscottl if (error == EINPROGRESS) { 2169157114Sscottl sc->mfi_flags |= MFI_FLAGS_QFRZN; 2170157114Sscottl return (0); 2171157114Sscottl } 2172157114Sscottl } else { 2173233711Sambrisko if (sc->MFA_enabled) 2174233711Sambrisko error = mfi_tbolt_send_frame(sc, cm); 2175233711Sambrisko else 2176233711Sambrisko error = mfi_send_frame(sc, cm); 2177157114Sscottl } 2178157114Sscottl 2179157114Sscottl return (error); 2180157114Sscottl} 2181157114Sscottl 2182157114Sscottlstatic void 2183157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 2184157114Sscottl{ 2185157114Sscottl struct mfi_frame_header *hdr; 2186157114Sscottl struct mfi_command *cm; 2187157237Sscottl union mfi_sgl *sgl; 2188157114Sscottl struct mfi_softc *sc; 2189225869Smav int i, j, first, dir; 2190233711Sambrisko int sge_size; 2191157114Sscottl 2192157114Sscottl cm = (struct mfi_command *)arg; 2193157114Sscottl sc = cm->cm_sc; 2194157237Sscottl hdr = &cm->cm_frame->header; 2195157237Sscottl sgl = cm->cm_sg; 2196157114Sscottl 2197170284Sambrisko if (error) { 2198170284Sambrisko printf("error %d in callback\n", error); 2199170284Sambrisko cm->cm_error = error; 2200170284Sambrisko mfi_complete(sc, cm); 2201170284Sambrisko return; 2202170284Sambrisko } 2203233711Sambrisko /* Use IEEE sgl only for IO's on a SKINNY controller 2204233711Sambrisko * For other commands on a SKINNY controller use either 2205233711Sambrisko * sg32 or sg64 based on the sizeof(bus_addr_t). 2206233711Sambrisko * Also calculate the total frame size based on the type 2207233711Sambrisko * of SGL used. 2208233711Sambrisko */ 2209233711Sambrisko if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) || 2210233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) || 2211233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) && 2212233711Sambrisko (sc->mfi_flags & MFI_FLAGS_SKINNY)) { 2213157237Sscottl for (i = 0; i < nsegs; i++) { 2214233711Sambrisko sgl->sg_skinny[i].addr = segs[i].ds_addr; 2215233711Sambrisko sgl->sg_skinny[i].len = segs[i].ds_len; 2216233711Sambrisko sgl->sg_skinny[i].flag = 0; 2217157114Sscottl } 2218233711Sambrisko hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64; 2219233711Sambrisko sge_size = sizeof(struct mfi_sg_skinny); 2220233711Sambrisko hdr->sg_count = nsegs; 2221157237Sscottl } else { 2222233711Sambrisko j = 0; 2223233711Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 2224233711Sambrisko first = cm->cm_stp_len; 2225233711Sambrisko if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { 2226233711Sambrisko sgl->sg32[j].addr = segs[0].ds_addr; 2227233711Sambrisko sgl->sg32[j++].len = first; 2228233711Sambrisko } else { 2229233711Sambrisko sgl->sg64[j].addr = segs[0].ds_addr; 2230233711Sambrisko sgl->sg64[j++].len = first; 2231233711Sambrisko } 2232233711Sambrisko } else 2233225869Smav first = 0; 2234233711Sambrisko if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { 2235233711Sambrisko for (i = 0; i < nsegs; i++) { 2236233711Sambrisko sgl->sg32[j].addr = segs[i].ds_addr + first; 2237233711Sambrisko sgl->sg32[j++].len = segs[i].ds_len - first; 2238233711Sambrisko first = 0; 2239233711Sambrisko } 2240233711Sambrisko } else { 2241233711Sambrisko for (i = 0; i < nsegs; i++) { 2242233711Sambrisko sgl->sg64[j].addr = segs[i].ds_addr + first; 2243233711Sambrisko sgl->sg64[j++].len = segs[i].ds_len - first; 2244233711Sambrisko first = 0; 2245233711Sambrisko } 2246233711Sambrisko hdr->flags |= MFI_FRAME_SGL64; 2247157237Sscottl } 2248233711Sambrisko hdr->sg_count = j; 2249233711Sambrisko sge_size = sc->mfi_sge_size; 2250157114Sscottl } 2251157114Sscottl 2252157114Sscottl dir = 0; 2253157114Sscottl if (cm->cm_flags & MFI_CMD_DATAIN) { 2254157114Sscottl dir |= BUS_DMASYNC_PREREAD; 2255157114Sscottl hdr->flags |= MFI_FRAME_DIR_READ; 2256157114Sscottl } 2257157114Sscottl if (cm->cm_flags & MFI_CMD_DATAOUT) { 2258157114Sscottl dir |= BUS_DMASYNC_PREWRITE; 2259157114Sscottl hdr->flags |= MFI_FRAME_DIR_WRITE; 2260157114Sscottl } 2261157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir); 2262157114Sscottl cm->cm_flags |= MFI_CMD_MAPPED; 2263157114Sscottl 2264157114Sscottl /* 2265157114Sscottl * Instead of calculating the total number of frames in the 2266157114Sscottl * compound frame, it's already assumed that there will be at 2267157114Sscottl * least 1 frame, so don't compensate for the modulo of the 2268157114Sscottl * following division. 2269157114Sscottl */ 2270162458Sscottl cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs); 2271157114Sscottl cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; 2272157114Sscottl 2273233711Sambrisko if (sc->MFA_enabled) 2274233711Sambrisko mfi_tbolt_send_frame(sc, cm); 2275233711Sambrisko else 2276233711Sambrisko mfi_send_frame(sc, cm); 2277157114Sscottl 2278157114Sscottl return; 2279157114Sscottl} 2280157114Sscottl 2281157114Sscottlstatic int 2282157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm) 2283157114Sscottl{ 2284164375Sscottl struct mfi_frame_header *hdr; 2285165225Sambrisko int tm = MFI_POLL_TIMEOUT_SECS * 1000; 2286157114Sscottl 2287164375Sscottl hdr = &cm->cm_frame->header; 2288164375Sscottl 2289164375Sscottl if ((cm->cm_flags & MFI_CMD_POLLED) == 0) { 2290164375Sscottl cm->cm_timestamp = time_uptime; 2291164375Sscottl mfi_enqueue_busy(cm); 2292164375Sscottl } else { 2293224039Sjhb hdr->cmd_status = MFI_STAT_INVALID_STATUS; 2294164375Sscottl hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 2295164375Sscottl } 2296164375Sscottl 2297157114Sscottl /* 2298157114Sscottl * The bus address of the command is aligned on a 64 byte boundary, 2299157114Sscottl * leaving the least 6 bits as zero. For whatever reason, the 2300157114Sscottl * hardware wants the address shifted right by three, leaving just 2301162458Sscottl * 3 zero bits. These three bits are then used as a prefetching 2302162458Sscottl * hint for the hardware to predict how many frames need to be 2303162458Sscottl * fetched across the bus. If a command has more than 8 frames 2304162458Sscottl * then the 3 bits are set to 0x7 and the firmware uses other 2305162458Sscottl * information in the command to determine the total amount to fetch. 2306162458Sscottl * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames 2307162458Sscottl * is enough for both 32bit and 64bit systems. 2308157114Sscottl */ 2309162458Sscottl if (cm->cm_extra_frames > 7) 2310162458Sscottl cm->cm_extra_frames = 7; 2311162458Sscottl 2312233711Sambrisko sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames); 2313164375Sscottl 2314164375Sscottl if ((cm->cm_flags & MFI_CMD_POLLED) == 0) 2315164375Sscottl return (0); 2316164375Sscottl 2317164375Sscottl /* This is a polled command, so busy-wait for it to complete. */ 2318224039Sjhb while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 2319164375Sscottl DELAY(1000); 2320165225Sambrisko tm -= 1; 2321164375Sscottl if (tm <= 0) 2322164375Sscottl break; 2323164375Sscottl } 2324164375Sscottl 2325224039Sjhb if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 2326165225Sambrisko device_printf(sc->mfi_dev, "Frame %p timed out " 2327233711Sambrisko "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode); 2328164375Sscottl return (ETIMEDOUT); 2329164375Sscottl } 2330164375Sscottl 2331157114Sscottl return (0); 2332157114Sscottl} 2333157114Sscottl 2334233711Sambrisko 2335233711Sambriskovoid 2336157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm) 2337157114Sscottl{ 2338157114Sscottl int dir; 2339157114Sscottl 2340157114Sscottl if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) { 2341157114Sscottl dir = 0; 2342225869Smav if ((cm->cm_flags & MFI_CMD_DATAIN) || 2343225869Smav (cm->cm_frame->header.cmd == MFI_CMD_STP)) 2344157114Sscottl dir |= BUS_DMASYNC_POSTREAD; 2345157114Sscottl if (cm->cm_flags & MFI_CMD_DATAOUT) 2346157114Sscottl dir |= BUS_DMASYNC_POSTWRITE; 2347157114Sscottl 2348157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir); 2349157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2350157114Sscottl cm->cm_flags &= ~MFI_CMD_MAPPED; 2351157114Sscottl } 2352157114Sscottl 2353170284Sambrisko cm->cm_flags |= MFI_CMD_COMPLETED; 2354170284Sambrisko 2355157114Sscottl if (cm->cm_complete != NULL) 2356157114Sscottl cm->cm_complete(cm); 2357159811Sps else 2358159811Sps wakeup(cm); 2359157114Sscottl} 2360157114Sscottl 2361158737Sambriskostatic int 2362158737Sambriskomfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort) 2363158737Sambrisko{ 2364158737Sambrisko struct mfi_command *cm; 2365158737Sambrisko struct mfi_abort_frame *abort; 2366165225Sambrisko int i = 0; 2367233711Sambrisko uint32_t context = 0; 2368158737Sambrisko 2369163398Sscottl mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2370163398Sscottl 2371158737Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 2372158737Sambrisko return (EBUSY); 2373158737Sambrisko } 2374158737Sambrisko 2375233711Sambrisko /* Zero out the MFI frame */ 2376233711Sambrisko context = cm->cm_frame->header.context; 2377233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2378233711Sambrisko cm->cm_frame->header.context = context; 2379233711Sambrisko 2380158737Sambrisko abort = &cm->cm_frame->abort; 2381158737Sambrisko abort->header.cmd = MFI_CMD_ABORT; 2382158737Sambrisko abort->header.flags = 0; 2383233711Sambrisko abort->header.scsi_status = 0; 2384158737Sambrisko abort->abort_context = cm_abort->cm_frame->header.context; 2385233711Sambrisko abort->abort_mfi_addr_lo = (uint32_t)cm_abort->cm_frame_busaddr; 2386233711Sambrisko abort->abort_mfi_addr_hi = 2387233711Sambrisko (uint32_t)((uint64_t)cm_abort->cm_frame_busaddr >> 32); 2388158737Sambrisko cm->cm_data = NULL; 2389164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 2390158737Sambrisko 2391233711Sambrisko if (sc->mfi_aen_cm) 2392235014Sambrisko sc->cm_aen_abort = 1; 2393235014Sambrisko if (sc->mfi_map_sync_cm) 2394235014Sambrisko sc->cm_map_abort = 1; 2395158737Sambrisko mfi_mapcmd(sc, cm); 2396158737Sambrisko mfi_release_command(cm); 2397158737Sambrisko 2398165225Sambrisko while (i < 5 && sc->mfi_aen_cm != NULL) { 2399233711Sambrisko msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", 2400233711Sambrisko 5 * hz); 2401165225Sambrisko i++; 2402158737Sambrisko } 2403235014Sambrisko while (i < 5 && sc->mfi_map_sync_cm != NULL) { 2404235014Sambrisko msleep(&sc->mfi_map_sync_cm, &sc->mfi_io_lock, 0, "mfiabort", 2405235014Sambrisko 5 * hz); 2406235014Sambrisko i++; 2407235014Sambrisko } 2408158737Sambrisko 2409158737Sambrisko return (0); 2410158737Sambrisko} 2411158737Sambrisko 2412157114Sscottlint 2413233711Sambriskomfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, 2414233711Sambrisko int len) 2415157114Sscottl{ 2416157114Sscottl struct mfi_command *cm; 2417157114Sscottl struct mfi_io_frame *io; 2418157114Sscottl int error; 2419233711Sambrisko uint32_t context = 0; 2420157114Sscottl 2421157114Sscottl if ((cm = mfi_dequeue_free(sc)) == NULL) 2422157114Sscottl return (EBUSY); 2423157114Sscottl 2424233711Sambrisko /* Zero out the MFI frame */ 2425233711Sambrisko context = cm->cm_frame->header.context; 2426233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2427233711Sambrisko cm->cm_frame->header.context = context; 2428233711Sambrisko 2429157114Sscottl io = &cm->cm_frame->io; 2430157114Sscottl io->header.cmd = MFI_CMD_LD_WRITE; 2431157114Sscottl io->header.target_id = id; 2432157114Sscottl io->header.timeout = 0; 2433157114Sscottl io->header.flags = 0; 2434233711Sambrisko io->header.scsi_status = 0; 2435157114Sscottl io->header.sense_len = MFI_SENSE_LEN; 2436157114Sscottl io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2437233711Sambrisko io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2438233711Sambrisko io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2439157114Sscottl io->lba_hi = (lba & 0xffffffff00000000) >> 32; 2440157114Sscottl io->lba_lo = lba & 0xffffffff; 2441157114Sscottl cm->cm_data = virt; 2442157114Sscottl cm->cm_len = len; 2443157114Sscottl cm->cm_sg = &io->sgl; 2444157114Sscottl cm->cm_total_frame_size = MFI_IO_FRAME_SIZE; 2445157114Sscottl cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT; 2446157114Sscottl 2447164375Sscottl error = mfi_mapcmd(sc, cm); 2448157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 2449157114Sscottl BUS_DMASYNC_POSTWRITE); 2450157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2451157114Sscottl mfi_release_command(cm); 2452157114Sscottl 2453157114Sscottl return (error); 2454157114Sscottl} 2455157114Sscottl 2456233711Sambriskoint 2457233711Sambriskomfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, 2458233711Sambrisko int len) 2459233711Sambrisko{ 2460233711Sambrisko struct mfi_command *cm; 2461233711Sambrisko struct mfi_pass_frame *pass; 2462233711Sambrisko int error; 2463233711Sambrisko int blkcount = 0; 2464233711Sambrisko 2465233711Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 2466233711Sambrisko return (EBUSY); 2467233711Sambrisko 2468233711Sambrisko pass = &cm->cm_frame->pass; 2469233711Sambrisko bzero(pass->cdb, 16); 2470233711Sambrisko pass->header.cmd = MFI_CMD_PD_SCSI_IO; 2471233711Sambrisko pass->cdb[0] = SCSI_WRITE; 2472233711Sambrisko pass->cdb[2] = (lba & 0xff000000) >> 24; 2473233711Sambrisko pass->cdb[3] = (lba & 0x00ff0000) >> 16; 2474233711Sambrisko pass->cdb[4] = (lba & 0x0000ff00) >> 8; 2475233711Sambrisko pass->cdb[5] = (lba & 0x000000ff); 2476233711Sambrisko blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2477233711Sambrisko pass->cdb[7] = (blkcount & 0xff00) >> 8; 2478233711Sambrisko pass->cdb[8] = (blkcount & 0x00ff); 2479233711Sambrisko pass->header.target_id = id; 2480233711Sambrisko pass->header.timeout = 0; 2481233711Sambrisko pass->header.flags = 0; 2482233711Sambrisko pass->header.scsi_status = 0; 2483233711Sambrisko pass->header.sense_len = MFI_SENSE_LEN; 2484233711Sambrisko pass->header.data_len = len; 2485233711Sambrisko pass->header.cdb_len = 10; 2486233711Sambrisko pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2487233711Sambrisko pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2488233711Sambrisko cm->cm_data = virt; 2489233711Sambrisko cm->cm_len = len; 2490233711Sambrisko cm->cm_sg = &pass->sgl; 2491233711Sambrisko cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; 2492233711Sambrisko cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT; 2493233711Sambrisko 2494233711Sambrisko error = mfi_mapcmd(sc, cm); 2495233711Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 2496233711Sambrisko BUS_DMASYNC_POSTWRITE); 2497233711Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2498233711Sambrisko mfi_release_command(cm); 2499233711Sambrisko 2500233711Sambrisko return (error); 2501233711Sambrisko} 2502233711Sambrisko 2503157114Sscottlstatic int 2504192450Simpmfi_open(struct cdev *dev, int flags, int fmt, struct thread *td) 2505157114Sscottl{ 2506157114Sscottl struct mfi_softc *sc; 2507171822Sjhb int error; 2508157114Sscottl 2509157114Sscottl sc = dev->si_drv1; 2510163398Sscottl 2511163398Sscottl mtx_lock(&sc->mfi_io_lock); 2512171822Sjhb if (sc->mfi_detaching) 2513171822Sjhb error = ENXIO; 2514171822Sjhb else { 2515171822Sjhb sc->mfi_flags |= MFI_FLAGS_OPEN; 2516171822Sjhb error = 0; 2517171822Sjhb } 2518163398Sscottl mtx_unlock(&sc->mfi_io_lock); 2519157114Sscottl 2520171822Sjhb return (error); 2521157114Sscottl} 2522157114Sscottl 2523157114Sscottlstatic int 2524192450Simpmfi_close(struct cdev *dev, int flags, int fmt, struct thread *td) 2525157114Sscottl{ 2526157114Sscottl struct mfi_softc *sc; 2527163398Sscottl struct mfi_aen *mfi_aen_entry, *tmp; 2528157114Sscottl 2529157114Sscottl sc = dev->si_drv1; 2530163398Sscottl 2531163398Sscottl mtx_lock(&sc->mfi_io_lock); 2532157114Sscottl sc->mfi_flags &= ~MFI_FLAGS_OPEN; 2533157114Sscottl 2534163398Sscottl TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) { 2535158737Sambrisko if (mfi_aen_entry->p == curproc) { 2536158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 2537158737Sambrisko aen_link); 2538158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 2539158737Sambrisko } 2540158737Sambrisko } 2541163398Sscottl mtx_unlock(&sc->mfi_io_lock); 2542157114Sscottl return (0); 2543157114Sscottl} 2544157114Sscottl 2545157114Sscottlstatic int 2546171821Sjhbmfi_config_lock(struct mfi_softc *sc, uint32_t opcode) 2547171821Sjhb{ 2548171821Sjhb 2549171821Sjhb switch (opcode) { 2550171821Sjhb case MFI_DCMD_LD_DELETE: 2551171821Sjhb case MFI_DCMD_CFG_ADD: 2552171821Sjhb case MFI_DCMD_CFG_CLEAR: 2553240962Sjhb case MFI_DCMD_CFG_FOREIGN_IMPORT: 2554171821Sjhb sx_xlock(&sc->mfi_config_lock); 2555171821Sjhb return (1); 2556171821Sjhb default: 2557171821Sjhb return (0); 2558171821Sjhb } 2559171821Sjhb} 2560171821Sjhb 2561171821Sjhbstatic void 2562171821Sjhbmfi_config_unlock(struct mfi_softc *sc, int locked) 2563171821Sjhb{ 2564171821Sjhb 2565171821Sjhb if (locked) 2566171821Sjhb sx_xunlock(&sc->mfi_config_lock); 2567171821Sjhb} 2568171821Sjhb 2569233711Sambrisko/* 2570233711Sambrisko * Perform pre-issue checks on commands from userland and possibly veto 2571233711Sambrisko * them. 2572233711Sambrisko */ 2573171821Sjhbstatic int 2574171821Sjhbmfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm) 2575171821Sjhb{ 2576171821Sjhb struct mfi_disk *ld, *ld2; 2577171821Sjhb int error; 2578233711Sambrisko struct mfi_system_pd *syspd = NULL; 2579233711Sambrisko uint16_t syspd_id; 2580233711Sambrisko uint16_t *mbox; 2581171821Sjhb 2582171821Sjhb mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2583171821Sjhb error = 0; 2584171821Sjhb switch (cm->cm_frame->dcmd.opcode) { 2585171821Sjhb case MFI_DCMD_LD_DELETE: 2586171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2587171821Sjhb if (ld->ld_id == cm->cm_frame->dcmd.mbox[0]) 2588171821Sjhb break; 2589171821Sjhb } 2590171821Sjhb if (ld == NULL) 2591171821Sjhb error = ENOENT; 2592171821Sjhb else 2593171821Sjhb error = mfi_disk_disable(ld); 2594171821Sjhb break; 2595171821Sjhb case MFI_DCMD_CFG_CLEAR: 2596171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2597171821Sjhb error = mfi_disk_disable(ld); 2598171821Sjhb if (error) 2599171821Sjhb break; 2600171821Sjhb } 2601171821Sjhb if (error) { 2602171821Sjhb TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) { 2603171821Sjhb if (ld2 == ld) 2604171821Sjhb break; 2605171821Sjhb mfi_disk_enable(ld2); 2606171821Sjhb } 2607171821Sjhb } 2608171821Sjhb break; 2609233711Sambrisko case MFI_DCMD_PD_STATE_SET: 2610233711Sambrisko mbox = (uint16_t *) cm->cm_frame->dcmd.mbox; 2611233711Sambrisko syspd_id = mbox[0]; 2612233711Sambrisko if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { 2613233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { 2614233711Sambrisko if (syspd->pd_id == syspd_id) 2615233711Sambrisko break; 2616233711Sambrisko } 2617233711Sambrisko } 2618233711Sambrisko else 2619233711Sambrisko break; 2620233711Sambrisko if (syspd) 2621233711Sambrisko error = mfi_syspd_disable(syspd); 2622233711Sambrisko break; 2623171821Sjhb default: 2624171821Sjhb break; 2625171821Sjhb } 2626171821Sjhb return (error); 2627171821Sjhb} 2628171821Sjhb 2629171821Sjhb/* Perform post-issue checks on commands from userland. */ 2630171821Sjhbstatic void 2631171821Sjhbmfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm) 2632171821Sjhb{ 2633171821Sjhb struct mfi_disk *ld, *ldn; 2634233711Sambrisko struct mfi_system_pd *syspd = NULL; 2635233711Sambrisko uint16_t syspd_id; 2636233711Sambrisko uint16_t *mbox; 2637171821Sjhb 2638171821Sjhb switch (cm->cm_frame->dcmd.opcode) { 2639171821Sjhb case MFI_DCMD_LD_DELETE: 2640171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2641171821Sjhb if (ld->ld_id == cm->cm_frame->dcmd.mbox[0]) 2642171821Sjhb break; 2643171821Sjhb } 2644171821Sjhb KASSERT(ld != NULL, ("volume dissappeared")); 2645171821Sjhb if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { 2646171821Sjhb mtx_unlock(&sc->mfi_io_lock); 2647196403Sjhb mtx_lock(&Giant); 2648171821Sjhb device_delete_child(sc->mfi_dev, ld->ld_dev); 2649196403Sjhb mtx_unlock(&Giant); 2650171821Sjhb mtx_lock(&sc->mfi_io_lock); 2651171821Sjhb } else 2652171821Sjhb mfi_disk_enable(ld); 2653171821Sjhb break; 2654171821Sjhb case MFI_DCMD_CFG_CLEAR: 2655171821Sjhb if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { 2656171821Sjhb mtx_unlock(&sc->mfi_io_lock); 2657196403Sjhb mtx_lock(&Giant); 2658171821Sjhb TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) { 2659171821Sjhb device_delete_child(sc->mfi_dev, ld->ld_dev); 2660171821Sjhb } 2661196403Sjhb mtx_unlock(&Giant); 2662171821Sjhb mtx_lock(&sc->mfi_io_lock); 2663171821Sjhb } else { 2664171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) 2665171821Sjhb mfi_disk_enable(ld); 2666171821Sjhb } 2667171821Sjhb break; 2668171821Sjhb case MFI_DCMD_CFG_ADD: 2669171821Sjhb mfi_ldprobe(sc); 2670171821Sjhb break; 2671184897Sambrisko case MFI_DCMD_CFG_FOREIGN_IMPORT: 2672184897Sambrisko mfi_ldprobe(sc); 2673184897Sambrisko break; 2674233711Sambrisko case MFI_DCMD_PD_STATE_SET: 2675233711Sambrisko mbox = (uint16_t *) cm->cm_frame->dcmd.mbox; 2676233711Sambrisko syspd_id = mbox[0]; 2677233711Sambrisko if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { 2678233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) { 2679233711Sambrisko if (syspd->pd_id == syspd_id) 2680233711Sambrisko break; 2681233711Sambrisko } 2682233711Sambrisko } 2683233711Sambrisko else 2684233711Sambrisko break; 2685233711Sambrisko /* If the transition fails then enable the syspd again */ 2686233711Sambrisko if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK) 2687233711Sambrisko mfi_syspd_enable(syspd); 2688233711Sambrisko break; 2689171821Sjhb } 2690171821Sjhb} 2691171821Sjhb 2692233711Sambriskostatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm) 2693233711Sambrisko{ 2694233711Sambrisko struct mfi_config_data *conf_data=(struct mfi_config_data *)cm->cm_data; 2695233711Sambrisko struct mfi_command *ld_cm = NULL; 2696233711Sambrisko struct mfi_ld_info *ld_info = NULL; 2697233711Sambrisko int error = 0; 2698233711Sambrisko 2699233711Sambrisko if ((cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) && 2700235016Sambrisko (conf_data->ld[0].params.isSSCD == 1)) { 2701233711Sambrisko error = 1; 2702233711Sambrisko } else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) { 2703233711Sambrisko error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO, 2704233711Sambrisko (void **)&ld_info, sizeof(*ld_info)); 2705235016Sambrisko if (error) { 2706233711Sambrisko device_printf(sc->mfi_dev, "Failed to allocate" 2707233711Sambrisko "MFI_DCMD_LD_GET_INFO %d", error); 2708233711Sambrisko if (ld_info) 2709233711Sambrisko free(ld_info, M_MFIBUF); 2710233711Sambrisko return 0; 2711233711Sambrisko } 2712233711Sambrisko ld_cm->cm_flags = MFI_CMD_DATAIN; 2713233711Sambrisko ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0]; 2714233711Sambrisko ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0]; 2715235016Sambrisko if (mfi_wait_command(sc, ld_cm) != 0) { 2716233711Sambrisko device_printf(sc->mfi_dev, "failed to get log drv\n"); 2717233711Sambrisko mfi_release_command(ld_cm); 2718233711Sambrisko free(ld_info, M_MFIBUF); 2719233711Sambrisko return 0; 2720233711Sambrisko } 2721233711Sambrisko 2722233711Sambrisko if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) { 2723233711Sambrisko free(ld_info, M_MFIBUF); 2724233711Sambrisko mfi_release_command(ld_cm); 2725233711Sambrisko return 0; 2726233711Sambrisko } 2727233711Sambrisko else 2728233711Sambrisko ld_info = (struct mfi_ld_info *)ld_cm->cm_private; 2729233711Sambrisko 2730233711Sambrisko if (ld_info->ld_config.params.isSSCD == 1) 2731233711Sambrisko error = 1; 2732233711Sambrisko 2733233711Sambrisko mfi_release_command(ld_cm); 2734233711Sambrisko free(ld_info, M_MFIBUF); 2735233711Sambrisko 2736233711Sambrisko } 2737233711Sambrisko return error; 2738233711Sambrisko} 2739233711Sambrisko 2740171821Sjhbstatic int 2741233711Sambriskomfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg) 2742233711Sambrisko{ 2743233711Sambrisko uint8_t i; 2744233711Sambrisko struct mfi_ioc_packet *ioc; 2745233711Sambrisko ioc = (struct mfi_ioc_packet *)arg; 2746233711Sambrisko int sge_size, error; 2747233711Sambrisko struct megasas_sge *kern_sge; 2748233711Sambrisko 2749233711Sambrisko memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr)); 2750233711Sambrisko kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off); 2751233711Sambrisko cm->cm_frame->header.sg_count = ioc->mfi_sge_count; 2752233711Sambrisko 2753233711Sambrisko if (sizeof(bus_addr_t) == 8) { 2754233711Sambrisko cm->cm_frame->header.flags |= MFI_FRAME_SGL64; 2755233711Sambrisko cm->cm_extra_frames = 2; 2756233711Sambrisko sge_size = sizeof(struct mfi_sg64); 2757233711Sambrisko } else { 2758233711Sambrisko cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; 2759233711Sambrisko sge_size = sizeof(struct mfi_sg32); 2760233711Sambrisko } 2761233711Sambrisko 2762233711Sambrisko cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count); 2763233711Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 2764233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 2765233711Sambrisko 1, 0, /* algnmnt, boundary */ 2766233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 2767233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 2768233711Sambrisko NULL, NULL, /* filter, filterarg */ 2769233711Sambrisko ioc->mfi_sgl[i].iov_len,/* maxsize */ 2770233711Sambrisko 2, /* nsegments */ 2771233711Sambrisko ioc->mfi_sgl[i].iov_len,/* maxsegsize */ 2772233711Sambrisko BUS_DMA_ALLOCNOW, /* flags */ 2773233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 2774233711Sambrisko &sc->mfi_kbuff_arr_dmat[i])) { 2775233711Sambrisko device_printf(sc->mfi_dev, 2776233711Sambrisko "Cannot allocate mfi_kbuff_arr_dmat tag\n"); 2777233711Sambrisko return (ENOMEM); 2778233711Sambrisko } 2779233711Sambrisko 2780233711Sambrisko if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i], 2781233711Sambrisko (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT, 2782233711Sambrisko &sc->mfi_kbuff_arr_dmamap[i])) { 2783233711Sambrisko device_printf(sc->mfi_dev, 2784233711Sambrisko "Cannot allocate mfi_kbuff_arr_dmamap memory\n"); 2785233711Sambrisko return (ENOMEM); 2786233711Sambrisko } 2787233711Sambrisko 2788233711Sambrisko bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i], 2789233711Sambrisko sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i], 2790233711Sambrisko ioc->mfi_sgl[i].iov_len, mfi_addr_cb, 2791233711Sambrisko &sc->mfi_kbuff_arr_busaddr[i], 0); 2792233711Sambrisko 2793233711Sambrisko if (!sc->kbuff_arr[i]) { 2794233711Sambrisko device_printf(sc->mfi_dev, 2795233711Sambrisko "Could not allocate memory for kbuff_arr info\n"); 2796233711Sambrisko return -1; 2797233711Sambrisko } 2798233711Sambrisko kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i]; 2799233711Sambrisko kern_sge[i].length = ioc->mfi_sgl[i].iov_len; 2800233711Sambrisko 2801233711Sambrisko if (sizeof(bus_addr_t) == 8) { 2802233711Sambrisko cm->cm_frame->stp.sgl.sg64[i].addr = 2803233711Sambrisko kern_sge[i].phys_addr; 2804233711Sambrisko cm->cm_frame->stp.sgl.sg64[i].len = 2805233711Sambrisko ioc->mfi_sgl[i].iov_len; 2806233711Sambrisko } else { 2807233711Sambrisko cm->cm_frame->stp.sgl.sg32[i].len = 2808233711Sambrisko kern_sge[i].phys_addr; 2809233711Sambrisko cm->cm_frame->stp.sgl.sg32[i].len = 2810233711Sambrisko ioc->mfi_sgl[i].iov_len; 2811233711Sambrisko } 2812233711Sambrisko 2813233711Sambrisko error = copyin(ioc->mfi_sgl[i].iov_base, 2814233711Sambrisko sc->kbuff_arr[i], 2815233711Sambrisko ioc->mfi_sgl[i].iov_len); 2816233711Sambrisko if (error != 0) { 2817233711Sambrisko device_printf(sc->mfi_dev, "Copy in failed\n"); 2818233711Sambrisko return error; 2819233711Sambrisko } 2820233711Sambrisko } 2821233711Sambrisko 2822233711Sambrisko cm->cm_flags |=MFI_CMD_MAPPED; 2823233711Sambrisko return 0; 2824233711Sambrisko} 2825233711Sambrisko 2826233711Sambriskostatic int 2827178968Sscottlmfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc) 2828178968Sscottl{ 2829178968Sscottl struct mfi_command *cm; 2830178968Sscottl struct mfi_dcmd_frame *dcmd; 2831178968Sscottl void *ioc_buf = NULL; 2832178968Sscottl uint32_t context; 2833178968Sscottl int error = 0, locked; 2834178968Sscottl 2835178968Sscottl 2836178968Sscottl if (ioc->buf_size > 0) { 2837238077Sjhb if (ioc->buf_size > 1024 * 1024) 2838238077Sjhb return (ENOMEM); 2839178968Sscottl ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK); 2840178968Sscottl error = copyin(ioc->buf, ioc_buf, ioc->buf_size); 2841178968Sscottl if (error) { 2842178968Sscottl device_printf(sc->mfi_dev, "failed to copyin\n"); 2843178968Sscottl free(ioc_buf, M_MFIBUF); 2844178968Sscottl return (error); 2845178968Sscottl } 2846178968Sscottl } 2847178968Sscottl 2848178968Sscottl locked = mfi_config_lock(sc, ioc->ioc_frame.opcode); 2849178968Sscottl 2850178968Sscottl mtx_lock(&sc->mfi_io_lock); 2851178968Sscottl while ((cm = mfi_dequeue_free(sc)) == NULL) 2852178968Sscottl msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz); 2853178968Sscottl 2854178968Sscottl /* Save context for later */ 2855178968Sscottl context = cm->cm_frame->header.context; 2856178968Sscottl 2857178968Sscottl dcmd = &cm->cm_frame->dcmd; 2858178968Sscottl bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame)); 2859178968Sscottl 2860178968Sscottl cm->cm_sg = &dcmd->sgl; 2861178968Sscottl cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 2862178968Sscottl cm->cm_data = ioc_buf; 2863178968Sscottl cm->cm_len = ioc->buf_size; 2864178968Sscottl 2865178968Sscottl /* restore context */ 2866178968Sscottl cm->cm_frame->header.context = context; 2867178968Sscottl 2868178968Sscottl /* Cheat since we don't know if we're writing or reading */ 2869178968Sscottl cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT; 2870178968Sscottl 2871178968Sscottl error = mfi_check_command_pre(sc, cm); 2872178968Sscottl if (error) 2873178968Sscottl goto out; 2874178968Sscottl 2875178968Sscottl error = mfi_wait_command(sc, cm); 2876178968Sscottl if (error) { 2877178968Sscottl device_printf(sc->mfi_dev, "ioctl failed %d\n", error); 2878178968Sscottl goto out; 2879178968Sscottl } 2880178968Sscottl bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame)); 2881178968Sscottl mfi_check_command_post(sc, cm); 2882178968Sscottlout: 2883178968Sscottl mfi_release_command(cm); 2884178968Sscottl mtx_unlock(&sc->mfi_io_lock); 2885178968Sscottl mfi_config_unlock(sc, locked); 2886178968Sscottl if (ioc->buf_size > 0) 2887178968Sscottl error = copyout(ioc_buf, ioc->buf, ioc->buf_size); 2888178968Sscottl if (ioc_buf) 2889178968Sscottl free(ioc_buf, M_MFIBUF); 2890178968Sscottl return (error); 2891178968Sscottl} 2892178968Sscottl 2893178968Sscottl#define PTRIN(p) ((void *)(uintptr_t)(p)) 2894178968Sscottl 2895178968Sscottlstatic int 2896192450Simpmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 2897157114Sscottl{ 2898157114Sscottl struct mfi_softc *sc; 2899157114Sscottl union mfi_statrequest *ms; 2900164281Sambrisko struct mfi_ioc_packet *ioc; 2901233711Sambrisko#ifdef COMPAT_FREEBSD32 2902179392Sambrisko struct mfi_ioc_packet32 *ioc32; 2903179392Sambrisko#endif 2904164281Sambrisko struct mfi_ioc_aen *aen; 2905164281Sambrisko struct mfi_command *cm = NULL; 2906233711Sambrisko uint32_t context = 0; 2907184897Sambrisko union mfi_sense_ptr sense_ptr; 2908233711Sambrisko uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0; 2909225869Smav size_t len; 2910233711Sambrisko int i, res; 2911178968Sscottl struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg; 2912233711Sambrisko#ifdef COMPAT_FREEBSD32 2913178968Sscottl struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg; 2914178968Sscottl struct mfi_ioc_passthru iop_swab; 2915178968Sscottl#endif 2916171821Sjhb int error, locked; 2917233711Sambrisko union mfi_sgl *sgl; 2918157114Sscottl sc = dev->si_drv1; 2919157114Sscottl error = 0; 2920157114Sscottl 2921233711Sambrisko if (sc->adpreset) 2922233711Sambrisko return EBUSY; 2923233711Sambrisko 2924233711Sambrisko if (sc->hw_crit_error) 2925233711Sambrisko return EBUSY; 2926233711Sambrisko 2927233711Sambrisko if (sc->issuepend_done == 0) 2928233711Sambrisko return EBUSY; 2929233711Sambrisko 2930157114Sscottl switch (cmd) { 2931157114Sscottl case MFIIO_STATS: 2932157114Sscottl ms = (union mfi_statrequest *)arg; 2933157114Sscottl switch (ms->ms_item) { 2934157114Sscottl case MFIQ_FREE: 2935157114Sscottl case MFIQ_BIO: 2936157114Sscottl case MFIQ_READY: 2937157114Sscottl case MFIQ_BUSY: 2938157114Sscottl bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat, 2939157114Sscottl sizeof(struct mfi_qstat)); 2940157114Sscottl break; 2941157114Sscottl default: 2942158737Sambrisko error = ENOIOCTL; 2943157114Sscottl break; 2944157114Sscottl } 2945157114Sscottl break; 2946169451Sscottl case MFIIO_QUERY_DISK: 2947169451Sscottl { 2948169451Sscottl struct mfi_query_disk *qd; 2949169451Sscottl struct mfi_disk *ld; 2950169451Sscottl 2951169451Sscottl qd = (struct mfi_query_disk *)arg; 2952169451Sscottl mtx_lock(&sc->mfi_io_lock); 2953169451Sscottl TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2954169451Sscottl if (ld->ld_id == qd->array_id) 2955169451Sscottl break; 2956169451Sscottl } 2957169451Sscottl if (ld == NULL) { 2958169451Sscottl qd->present = 0; 2959169451Sscottl mtx_unlock(&sc->mfi_io_lock); 2960169451Sscottl return (0); 2961169451Sscottl } 2962169451Sscottl qd->present = 1; 2963169451Sscottl if (ld->ld_flags & MFI_DISK_FLAGS_OPEN) 2964169451Sscottl qd->open = 1; 2965169451Sscottl bzero(qd->devname, SPECNAMELEN + 1); 2966169451Sscottl snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit); 2967169451Sscottl mtx_unlock(&sc->mfi_io_lock); 2968169451Sscottl break; 2969169451Sscottl } 2970164281Sambrisko case MFI_CMD: 2971233711Sambrisko#ifdef COMPAT_FREEBSD32 2972179392Sambrisko case MFI_CMD32: 2973179392Sambrisko#endif 2974177489Sambrisko { 2975177489Sambrisko devclass_t devclass; 2976164281Sambrisko ioc = (struct mfi_ioc_packet *)arg; 2977177489Sambrisko int adapter; 2978164281Sambrisko 2979177489Sambrisko adapter = ioc->mfi_adapter_no; 2980177489Sambrisko if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) { 2981177489Sambrisko devclass = devclass_find("mfi"); 2982177489Sambrisko sc = devclass_get_softc(devclass, adapter); 2983177489Sambrisko } 2984164281Sambrisko mtx_lock(&sc->mfi_io_lock); 2985164281Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 2986164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 2987164281Sambrisko return (EBUSY); 2988164281Sambrisko } 2989164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 2990171821Sjhb locked = 0; 2991164281Sambrisko 2992164281Sambrisko /* 2993164281Sambrisko * save off original context since copying from user 2994164281Sambrisko * will clobber some data 2995164281Sambrisko */ 2996164281Sambrisko context = cm->cm_frame->header.context; 2997233711Sambrisko cm->cm_frame->header.context = cm->cm_index; 2998164281Sambrisko 2999165225Sambrisko bcopy(ioc->mfi_frame.raw, cm->cm_frame, 3000233711Sambrisko 2 * MEGAMFI_FRAME_SIZE); 3001184897Sambrisko cm->cm_total_frame_size = (sizeof(union mfi_sgl) 3002184897Sambrisko * ioc->mfi_sge_count) + ioc->mfi_sgl_off; 3003233711Sambrisko cm->cm_frame->header.scsi_status = 0; 3004233711Sambrisko cm->cm_frame->header.pad0 = 0; 3005175897Sambrisko if (ioc->mfi_sge_count) { 3006175897Sambrisko cm->cm_sg = 3007175897Sambrisko (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off]; 3008175897Sambrisko } 3009233711Sambrisko sgl = cm->cm_sg; 3010175897Sambrisko cm->cm_flags = 0; 3011175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN) 3012175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN; 3013175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT) 3014175897Sambrisko cm->cm_flags |= MFI_CMD_DATAOUT; 3015175897Sambrisko /* Legacy app shim */ 3016175897Sambrisko if (cm->cm_flags == 0) 3017175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT; 3018164281Sambrisko cm->cm_len = cm->cm_frame->header.data_len; 3019225869Smav if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3020233711Sambrisko#ifdef COMPAT_FREEBSD32 3021225869Smav if (cmd == MFI_CMD) { 3022225869Smav#endif 3023225869Smav /* Native */ 3024225869Smav cm->cm_stp_len = ioc->mfi_sgl[0].iov_len; 3025233711Sambrisko#ifdef COMPAT_FREEBSD32 3026225869Smav } else { 3027225869Smav /* 32bit on 64bit */ 3028225869Smav ioc32 = (struct mfi_ioc_packet32 *)ioc; 3029225869Smav cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len; 3030225869Smav } 3031225869Smav#endif 3032225869Smav cm->cm_len += cm->cm_stp_len; 3033225869Smav } 3034184897Sambrisko if (cm->cm_len && 3035184897Sambrisko (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) { 3036175897Sambrisko cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF, 3037175897Sambrisko M_WAITOK | M_ZERO); 3038175897Sambrisko if (cm->cm_data == NULL) { 3039175897Sambrisko device_printf(sc->mfi_dev, "Malloc failed\n"); 3040175897Sambrisko goto out; 3041175897Sambrisko } 3042175897Sambrisko } else { 3043175897Sambrisko cm->cm_data = 0; 3044165225Sambrisko } 3045164281Sambrisko 3046164281Sambrisko /* restore header context */ 3047164281Sambrisko cm->cm_frame->header.context = context; 3048164281Sambrisko 3049233711Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3050233711Sambrisko res = mfi_stp_cmd(sc, cm, arg); 3051233711Sambrisko if (res != 0) 3052233711Sambrisko goto out; 3053233711Sambrisko } else { 3054233711Sambrisko temp = data; 3055233711Sambrisko if ((cm->cm_flags & MFI_CMD_DATAOUT) || 3056233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_STP)) { 3057233711Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 3058233711Sambrisko#ifdef COMPAT_FREEBSD32 3059233711Sambrisko if (cmd == MFI_CMD) { 3060225869Smav#endif 3061233711Sambrisko /* Native */ 3062233711Sambrisko addr = ioc->mfi_sgl[i].iov_base; 3063233711Sambrisko len = ioc->mfi_sgl[i].iov_len; 3064233711Sambrisko#ifdef COMPAT_FREEBSD32 3065233711Sambrisko } else { 3066233711Sambrisko /* 32bit on 64bit */ 3067233711Sambrisko ioc32 = (struct mfi_ioc_packet32 *)ioc; 3068233711Sambrisko addr = PTRIN(ioc32->mfi_sgl[i].iov_base); 3069233711Sambrisko len = ioc32->mfi_sgl[i].iov_len; 3070233711Sambrisko } 3071179392Sambrisko#endif 3072233711Sambrisko error = copyin(addr, temp, len); 3073233711Sambrisko if (error != 0) { 3074233711Sambrisko device_printf(sc->mfi_dev, 3075233711Sambrisko "Copy in failed\n"); 3076233711Sambrisko goto out; 3077233711Sambrisko } 3078233711Sambrisko temp = &temp[len]; 3079175897Sambrisko } 3080164281Sambrisko } 3081164281Sambrisko } 3082164281Sambrisko 3083171821Sjhb if (cm->cm_frame->header.cmd == MFI_CMD_DCMD) 3084233711Sambrisko locked = mfi_config_lock(sc, 3085233711Sambrisko cm->cm_frame->dcmd.opcode); 3086171821Sjhb 3087184933Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { 3088233711Sambrisko cm->cm_frame->pass.sense_addr_lo = 3089233711Sambrisko (uint32_t)cm->cm_sense_busaddr; 3090233711Sambrisko cm->cm_frame->pass.sense_addr_hi = 3091233711Sambrisko (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 3092184933Sambrisko } 3093164281Sambrisko mtx_lock(&sc->mfi_io_lock); 3094233711Sambrisko skip_pre_post = mfi_check_for_sscd (sc, cm); 3095233711Sambrisko if (!skip_pre_post) { 3096233711Sambrisko error = mfi_check_command_pre(sc, cm); 3097233711Sambrisko if (error) { 3098233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 3099233711Sambrisko goto out; 3100233711Sambrisko } 3101171821Sjhb } 3102170284Sambrisko if ((error = mfi_wait_command(sc, cm)) != 0) { 3103164281Sambrisko device_printf(sc->mfi_dev, 3104165225Sambrisko "Controller polled failed\n"); 3105164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3106164281Sambrisko goto out; 3107164281Sambrisko } 3108233711Sambrisko if (!skip_pre_post) { 3109233711Sambrisko mfi_check_command_post(sc, cm); 3110233711Sambrisko } 3111164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3112164281Sambrisko 3113233711Sambrisko if (cm->cm_frame->header.cmd != MFI_CMD_STP) { 3114233711Sambrisko temp = data; 3115233711Sambrisko if ((cm->cm_flags & MFI_CMD_DATAIN) || 3116233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_STP)) { 3117233711Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 3118233711Sambrisko#ifdef COMPAT_FREEBSD32 3119233711Sambrisko if (cmd == MFI_CMD) { 3120225869Smav#endif 3121233711Sambrisko /* Native */ 3122233711Sambrisko addr = ioc->mfi_sgl[i].iov_base; 3123233711Sambrisko len = ioc->mfi_sgl[i].iov_len; 3124233711Sambrisko#ifdef COMPAT_FREEBSD32 3125233711Sambrisko } else { 3126233711Sambrisko /* 32bit on 64bit */ 3127233711Sambrisko ioc32 = (struct mfi_ioc_packet32 *)ioc; 3128233711Sambrisko addr = PTRIN(ioc32->mfi_sgl[i].iov_base); 3129233711Sambrisko len = ioc32->mfi_sgl[i].iov_len; 3130233711Sambrisko } 3131179392Sambrisko#endif 3132233711Sambrisko error = copyout(temp, addr, len); 3133233711Sambrisko if (error != 0) { 3134233711Sambrisko device_printf(sc->mfi_dev, 3135233711Sambrisko "Copy out failed\n"); 3136233711Sambrisko goto out; 3137233711Sambrisko } 3138233711Sambrisko temp = &temp[len]; 3139175897Sambrisko } 3140164281Sambrisko } 3141164281Sambrisko } 3142164281Sambrisko 3143165225Sambrisko if (ioc->mfi_sense_len) { 3144184897Sambrisko /* get user-space sense ptr then copy out sense */ 3145225428Sbz bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off], 3146184897Sambrisko &sense_ptr.sense_ptr_data[0], 3147184897Sambrisko sizeof(sense_ptr.sense_ptr_data)); 3148233711Sambrisko#ifdef COMPAT_FREEBSD32 3149184974Sambrisko if (cmd != MFI_CMD) { 3150184974Sambrisko /* 3151184974Sambrisko * not 64bit native so zero out any address 3152184974Sambrisko * over 32bit */ 3153184975Sambrisko sense_ptr.addr.high = 0; 3154184974Sambrisko } 3155184974Sambrisko#endif 3156184897Sambrisko error = copyout(cm->cm_sense, sense_ptr.user_space, 3157165225Sambrisko ioc->mfi_sense_len); 3158164281Sambrisko if (error != 0) { 3159164281Sambrisko device_printf(sc->mfi_dev, 3160165225Sambrisko "Copy out failed\n"); 3161164281Sambrisko goto out; 3162164281Sambrisko } 3163164281Sambrisko } 3164164281Sambrisko 3165165225Sambrisko ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status; 3166164281Sambriskoout: 3167171821Sjhb mfi_config_unlock(sc, locked); 3168164281Sambrisko if (data) 3169164281Sambrisko free(data, M_MFIBUF); 3170233711Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3171233711Sambrisko for (i = 0; i < 2; i++) { 3172233711Sambrisko if (sc->kbuff_arr[i]) { 3173233711Sambrisko if (sc->mfi_kbuff_arr_busaddr != 0) 3174233711Sambrisko bus_dmamap_unload( 3175233711Sambrisko sc->mfi_kbuff_arr_dmat[i], 3176233711Sambrisko sc->mfi_kbuff_arr_dmamap[i] 3177233711Sambrisko ); 3178233711Sambrisko if (sc->kbuff_arr[i] != NULL) 3179233711Sambrisko bus_dmamem_free( 3180233711Sambrisko sc->mfi_kbuff_arr_dmat[i], 3181233711Sambrisko sc->kbuff_arr[i], 3182233711Sambrisko sc->mfi_kbuff_arr_dmamap[i] 3183233711Sambrisko ); 3184233711Sambrisko if (sc->mfi_kbuff_arr_dmat[i] != NULL) 3185233711Sambrisko bus_dma_tag_destroy( 3186233711Sambrisko sc->mfi_kbuff_arr_dmat[i]); 3187233711Sambrisko } 3188233711Sambrisko } 3189233711Sambrisko } 3190164281Sambrisko if (cm) { 3191164281Sambrisko mtx_lock(&sc->mfi_io_lock); 3192164281Sambrisko mfi_release_command(cm); 3193164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3194164281Sambrisko } 3195164281Sambrisko 3196164281Sambrisko break; 3197177489Sambrisko } 3198164281Sambrisko case MFI_SET_AEN: 3199164281Sambrisko aen = (struct mfi_ioc_aen *)arg; 3200164281Sambrisko error = mfi_aen_register(sc, aen->aen_seq_num, 3201164281Sambrisko aen->aen_class_locale); 3202164281Sambrisko 3203164281Sambrisko break; 3204164281Sambrisko case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */ 3205158737Sambrisko { 3206158737Sambrisko devclass_t devclass; 3207158737Sambrisko struct mfi_linux_ioc_packet l_ioc; 3208158737Sambrisko int adapter; 3209158737Sambrisko 3210158737Sambrisko devclass = devclass_find("mfi"); 3211158737Sambrisko if (devclass == NULL) 3212158737Sambrisko return (ENOENT); 3213158737Sambrisko 3214158737Sambrisko error = copyin(arg, &l_ioc, sizeof(l_ioc)); 3215158737Sambrisko if (error) 3216158737Sambrisko return (error); 3217158737Sambrisko adapter = l_ioc.lioc_adapter_no; 3218158737Sambrisko sc = devclass_get_softc(devclass, adapter); 3219158737Sambrisko if (sc == NULL) 3220158737Sambrisko return (ENOENT); 3221158737Sambrisko return (mfi_linux_ioctl_int(sc->mfi_cdev, 3222158737Sambrisko cmd, arg, flag, td)); 3223158737Sambrisko break; 3224158737Sambrisko } 3225164281Sambrisko case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */ 3226158737Sambrisko { 3227158737Sambrisko devclass_t devclass; 3228158737Sambrisko struct mfi_linux_ioc_aen l_aen; 3229158737Sambrisko int adapter; 3230158737Sambrisko 3231158737Sambrisko devclass = devclass_find("mfi"); 3232158737Sambrisko if (devclass == NULL) 3233158737Sambrisko return (ENOENT); 3234158737Sambrisko 3235158737Sambrisko error = copyin(arg, &l_aen, sizeof(l_aen)); 3236158737Sambrisko if (error) 3237158737Sambrisko return (error); 3238158737Sambrisko adapter = l_aen.laen_adapter_no; 3239158737Sambrisko sc = devclass_get_softc(devclass, adapter); 3240158737Sambrisko if (sc == NULL) 3241158737Sambrisko return (ENOENT); 3242158737Sambrisko return (mfi_linux_ioctl_int(sc->mfi_cdev, 3243158737Sambrisko cmd, arg, flag, td)); 3244158737Sambrisko break; 3245158737Sambrisko } 3246233711Sambrisko#ifdef COMPAT_FREEBSD32 3247178968Sscottl case MFIIO_PASSTHRU32: 3248238077Sjhb if (!SV_CURPROC_FLAG(SV_ILP32)) { 3249238077Sjhb error = ENOTTY; 3250238077Sjhb break; 3251238077Sjhb } 3252178968Sscottl iop_swab.ioc_frame = iop32->ioc_frame; 3253178968Sscottl iop_swab.buf_size = iop32->buf_size; 3254178968Sscottl iop_swab.buf = PTRIN(iop32->buf); 3255178968Sscottl iop = &iop_swab; 3256178968Sscottl /* FALLTHROUGH */ 3257178968Sscottl#endif 3258178968Sscottl case MFIIO_PASSTHRU: 3259178968Sscottl error = mfi_user_command(sc, iop); 3260233711Sambrisko#ifdef COMPAT_FREEBSD32 3261178968Sscottl if (cmd == MFIIO_PASSTHRU32) 3262178968Sscottl iop32->ioc_frame = iop_swab.ioc_frame; 3263178968Sscottl#endif 3264178968Sscottl break; 3265157114Sscottl default: 3266163398Sscottl device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); 3267238077Sjhb error = ENOTTY; 3268157114Sscottl break; 3269157114Sscottl } 3270157114Sscottl 3271157114Sscottl return (error); 3272157114Sscottl} 3273158737Sambrisko 3274158737Sambriskostatic int 3275192450Simpmfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 3276158737Sambrisko{ 3277158737Sambrisko struct mfi_softc *sc; 3278158737Sambrisko struct mfi_linux_ioc_packet l_ioc; 3279158737Sambrisko struct mfi_linux_ioc_aen l_aen; 3280158737Sambrisko struct mfi_command *cm = NULL; 3281158737Sambrisko struct mfi_aen *mfi_aen_entry; 3282184897Sambrisko union mfi_sense_ptr sense_ptr; 3283233711Sambrisko uint32_t context = 0; 3284158737Sambrisko uint8_t *data = NULL, *temp; 3285158737Sambrisko int i; 3286171821Sjhb int error, locked; 3287158737Sambrisko 3288158737Sambrisko sc = dev->si_drv1; 3289158737Sambrisko error = 0; 3290158737Sambrisko switch (cmd) { 3291164281Sambrisko case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */ 3292158737Sambrisko error = copyin(arg, &l_ioc, sizeof(l_ioc)); 3293158737Sambrisko if (error != 0) 3294158737Sambrisko return (error); 3295158737Sambrisko 3296158737Sambrisko if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) { 3297158737Sambrisko return (EINVAL); 3298158737Sambrisko } 3299158737Sambrisko 3300158737Sambrisko mtx_lock(&sc->mfi_io_lock); 3301158737Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 3302158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3303158737Sambrisko return (EBUSY); 3304158737Sambrisko } 3305158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3306171821Sjhb locked = 0; 3307158737Sambrisko 3308158737Sambrisko /* 3309158737Sambrisko * save off original context since copying from user 3310158737Sambrisko * will clobber some data 3311158737Sambrisko */ 3312158737Sambrisko context = cm->cm_frame->header.context; 3313158737Sambrisko 3314158737Sambrisko bcopy(l_ioc.lioc_frame.raw, cm->cm_frame, 3315175897Sambrisko 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */ 3316184897Sambrisko cm->cm_total_frame_size = (sizeof(union mfi_sgl) 3317184897Sambrisko * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off; 3318233711Sambrisko cm->cm_frame->header.scsi_status = 0; 3319233711Sambrisko cm->cm_frame->header.pad0 = 0; 3320175897Sambrisko if (l_ioc.lioc_sge_count) 3321175897Sambrisko cm->cm_sg = 3322175897Sambrisko (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off]; 3323175897Sambrisko cm->cm_flags = 0; 3324175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN) 3325175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN; 3326175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT) 3327175897Sambrisko cm->cm_flags |= MFI_CMD_DATAOUT; 3328158737Sambrisko cm->cm_len = cm->cm_frame->header.data_len; 3329184897Sambrisko if (cm->cm_len && 3330184897Sambrisko (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) { 3331175897Sambrisko cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF, 3332175897Sambrisko M_WAITOK | M_ZERO); 3333175897Sambrisko if (cm->cm_data == NULL) { 3334175897Sambrisko device_printf(sc->mfi_dev, "Malloc failed\n"); 3335175897Sambrisko goto out; 3336175897Sambrisko } 3337175897Sambrisko } else { 3338175897Sambrisko cm->cm_data = 0; 3339175897Sambrisko } 3340158737Sambrisko 3341158737Sambrisko /* restore header context */ 3342158737Sambrisko cm->cm_frame->header.context = context; 3343158737Sambrisko 3344158737Sambrisko temp = data; 3345175897Sambrisko if (cm->cm_flags & MFI_CMD_DATAOUT) { 3346175897Sambrisko for (i = 0; i < l_ioc.lioc_sge_count; i++) { 3347178968Sscottl error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base), 3348175897Sambrisko temp, 3349175897Sambrisko l_ioc.lioc_sgl[i].iov_len); 3350175897Sambrisko if (error != 0) { 3351175897Sambrisko device_printf(sc->mfi_dev, 3352175897Sambrisko "Copy in failed\n"); 3353175897Sambrisko goto out; 3354175897Sambrisko } 3355175897Sambrisko temp = &temp[l_ioc.lioc_sgl[i].iov_len]; 3356158737Sambrisko } 3357158737Sambrisko } 3358158737Sambrisko 3359171821Sjhb if (cm->cm_frame->header.cmd == MFI_CMD_DCMD) 3360171821Sjhb locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode); 3361171821Sjhb 3362184933Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { 3363233711Sambrisko cm->cm_frame->pass.sense_addr_lo = 3364233711Sambrisko (uint32_t)cm->cm_sense_busaddr; 3365233711Sambrisko cm->cm_frame->pass.sense_addr_hi = 3366233711Sambrisko (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 3367184933Sambrisko } 3368184933Sambrisko 3369163398Sscottl mtx_lock(&sc->mfi_io_lock); 3370171821Sjhb error = mfi_check_command_pre(sc, cm); 3371171821Sjhb if (error) { 3372171821Sjhb mtx_unlock(&sc->mfi_io_lock); 3373171821Sjhb goto out; 3374171821Sjhb } 3375171821Sjhb 3376170284Sambrisko if ((error = mfi_wait_command(sc, cm)) != 0) { 3377158737Sambrisko device_printf(sc->mfi_dev, 3378165225Sambrisko "Controller polled failed\n"); 3379163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3380158737Sambrisko goto out; 3381158737Sambrisko } 3382158737Sambrisko 3383171821Sjhb mfi_check_command_post(sc, cm); 3384163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3385158737Sambrisko 3386158737Sambrisko temp = data; 3387175897Sambrisko if (cm->cm_flags & MFI_CMD_DATAIN) { 3388175897Sambrisko for (i = 0; i < l_ioc.lioc_sge_count; i++) { 3389175897Sambrisko error = copyout(temp, 3390178968Sscottl PTRIN(l_ioc.lioc_sgl[i].iov_base), 3391175897Sambrisko l_ioc.lioc_sgl[i].iov_len); 3392175897Sambrisko if (error != 0) { 3393175897Sambrisko device_printf(sc->mfi_dev, 3394175897Sambrisko "Copy out failed\n"); 3395175897Sambrisko goto out; 3396175897Sambrisko } 3397175897Sambrisko temp = &temp[l_ioc.lioc_sgl[i].iov_len]; 3398158737Sambrisko } 3399158737Sambrisko } 3400158737Sambrisko 3401158737Sambrisko if (l_ioc.lioc_sense_len) { 3402184897Sambrisko /* get user-space sense ptr then copy out sense */ 3403184897Sambrisko bcopy(&((struct mfi_linux_ioc_packet*)arg) 3404184897Sambrisko ->lioc_frame.raw[l_ioc.lioc_sense_off], 3405184897Sambrisko &sense_ptr.sense_ptr_data[0], 3406184897Sambrisko sizeof(sense_ptr.sense_ptr_data)); 3407184974Sambrisko#ifdef __amd64__ 3408184974Sambrisko /* 3409184974Sambrisko * only 32bit Linux support so zero out any 3410184974Sambrisko * address over 32bit 3411184974Sambrisko */ 3412184975Sambrisko sense_ptr.addr.high = 0; 3413184974Sambrisko#endif 3414184897Sambrisko error = copyout(cm->cm_sense, sense_ptr.user_space, 3415158737Sambrisko l_ioc.lioc_sense_len); 3416158737Sambrisko if (error != 0) { 3417158737Sambrisko device_printf(sc->mfi_dev, 3418165225Sambrisko "Copy out failed\n"); 3419158737Sambrisko goto out; 3420158737Sambrisko } 3421158737Sambrisko } 3422158737Sambrisko 3423158737Sambrisko error = copyout(&cm->cm_frame->header.cmd_status, 3424158737Sambrisko &((struct mfi_linux_ioc_packet*)arg) 3425158737Sambrisko ->lioc_frame.hdr.cmd_status, 3426158737Sambrisko 1); 3427158737Sambrisko if (error != 0) { 3428158737Sambrisko device_printf(sc->mfi_dev, 3429165225Sambrisko "Copy out failed\n"); 3430158737Sambrisko goto out; 3431158737Sambrisko } 3432158737Sambrisko 3433158737Sambriskoout: 3434171821Sjhb mfi_config_unlock(sc, locked); 3435158737Sambrisko if (data) 3436158737Sambrisko free(data, M_MFIBUF); 3437158737Sambrisko if (cm) { 3438158737Sambrisko mtx_lock(&sc->mfi_io_lock); 3439158737Sambrisko mfi_release_command(cm); 3440158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3441158737Sambrisko } 3442158737Sambrisko 3443158737Sambrisko return (error); 3444164281Sambrisko case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */ 3445158737Sambrisko error = copyin(arg, &l_aen, sizeof(l_aen)); 3446158737Sambrisko if (error != 0) 3447158737Sambrisko return (error); 3448158737Sambrisko printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid); 3449158737Sambrisko mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF, 3450158737Sambrisko M_WAITOK); 3451163398Sscottl mtx_lock(&sc->mfi_io_lock); 3452158737Sambrisko if (mfi_aen_entry != NULL) { 3453158737Sambrisko mfi_aen_entry->p = curproc; 3454158737Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry, 3455158737Sambrisko aen_link); 3456158737Sambrisko } 3457158737Sambrisko error = mfi_aen_register(sc, l_aen.laen_seq_num, 3458158737Sambrisko l_aen.laen_class_locale); 3459158737Sambrisko 3460158737Sambrisko if (error != 0) { 3461158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 3462158737Sambrisko aen_link); 3463158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 3464158737Sambrisko } 3465163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3466158737Sambrisko 3467158737Sambrisko return (error); 3468158737Sambrisko default: 3469158737Sambrisko device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); 3470158737Sambrisko error = ENOENT; 3471158737Sambrisko break; 3472158737Sambrisko } 3473158737Sambrisko 3474158737Sambrisko return (error); 3475158737Sambrisko} 3476158737Sambrisko 3477158737Sambriskostatic int 3478158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td) 3479158737Sambrisko{ 3480158737Sambrisko struct mfi_softc *sc; 3481158737Sambrisko int revents = 0; 3482158737Sambrisko 3483158737Sambrisko sc = dev->si_drv1; 3484158737Sambrisko 3485158737Sambrisko if (poll_events & (POLLIN | POLLRDNORM)) { 3486163398Sscottl if (sc->mfi_aen_triggered != 0) { 3487158737Sambrisko revents |= poll_events & (POLLIN | POLLRDNORM); 3488163398Sscottl sc->mfi_aen_triggered = 0; 3489163398Sscottl } 3490158737Sambrisko if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) { 3491158737Sambrisko revents |= POLLERR; 3492158737Sambrisko } 3493158737Sambrisko } 3494158737Sambrisko 3495158737Sambrisko if (revents == 0) { 3496158737Sambrisko if (poll_events & (POLLIN | POLLRDNORM)) { 3497158737Sambrisko sc->mfi_poll_waiting = 1; 3498158737Sambrisko selrecord(td, &sc->mfi_select); 3499158737Sambrisko } 3500158737Sambrisko } 3501158737Sambrisko 3502158737Sambrisko return revents; 3503158737Sambrisko} 3504162619Sscottl 3505162619Sscottlstatic void 3506163398Sscottlmfi_dump_all(void) 3507163398Sscottl{ 3508163398Sscottl struct mfi_softc *sc; 3509163398Sscottl struct mfi_command *cm; 3510163398Sscottl devclass_t dc; 3511163398Sscottl time_t deadline; 3512163398Sscottl int timedout; 3513163398Sscottl int i; 3514163398Sscottl 3515163398Sscottl dc = devclass_find("mfi"); 3516163398Sscottl if (dc == NULL) { 3517163398Sscottl printf("No mfi dev class\n"); 3518163398Sscottl return; 3519163398Sscottl } 3520163398Sscottl 3521163398Sscottl for (i = 0; ; i++) { 3522163398Sscottl sc = devclass_get_softc(dc, i); 3523163398Sscottl if (sc == NULL) 3524163398Sscottl break; 3525163398Sscottl device_printf(sc->mfi_dev, "Dumping\n\n"); 3526163398Sscottl timedout = 0; 3527163398Sscottl deadline = time_uptime - MFI_CMD_TIMEOUT; 3528163398Sscottl mtx_lock(&sc->mfi_io_lock); 3529163398Sscottl TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) { 3530163398Sscottl if (cm->cm_timestamp < deadline) { 3531163398Sscottl device_printf(sc->mfi_dev, 3532233711Sambrisko "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 3533233711Sambrisko cm, (int)(time_uptime - cm->cm_timestamp)); 3534163398Sscottl MFI_PRINT_CMD(cm); 3535163398Sscottl timedout++; 3536163398Sscottl } 3537163398Sscottl } 3538163398Sscottl 3539163398Sscottl#if 0 3540163398Sscottl if (timedout) 3541163398Sscottl MFI_DUMP_CMDS(SC); 3542163398Sscottl#endif 3543163398Sscottl 3544163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3545163398Sscottl } 3546163398Sscottl 3547163398Sscottl return; 3548163398Sscottl} 3549163398Sscottl 3550163398Sscottlstatic void 3551162619Sscottlmfi_timeout(void *data) 3552162619Sscottl{ 3553162619Sscottl struct mfi_softc *sc = (struct mfi_softc *)data; 3554162619Sscottl struct mfi_command *cm; 3555162619Sscottl time_t deadline; 3556162619Sscottl int timedout = 0; 3557162619Sscottl 3558162619Sscottl deadline = time_uptime - MFI_CMD_TIMEOUT; 3559233711Sambrisko if (sc->adpreset == 0) { 3560233711Sambrisko if (!mfi_tbolt_reset(sc)) { 3561233711Sambrisko callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, mfi_timeout, sc); 3562233711Sambrisko return; 3563233711Sambrisko } 3564233711Sambrisko } 3565162619Sscottl mtx_lock(&sc->mfi_io_lock); 3566162619Sscottl TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) { 3567235014Sambrisko if (sc->mfi_aen_cm == cm || sc->mfi_map_sync_cm == cm) 3568162688Sscottl continue; 3569235014Sambrisko if (cm->cm_timestamp < deadline) { 3570233711Sambrisko if (sc->adpreset != 0 && sc->issuepend_done == 0) { 3571233711Sambrisko cm->cm_timestamp = time_uptime; 3572233711Sambrisko } else { 3573233711Sambrisko device_printf(sc->mfi_dev, 3574233711Sambrisko "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 3575233711Sambrisko cm, (int)(time_uptime - cm->cm_timestamp) 3576233711Sambrisko ); 3577233711Sambrisko MFI_PRINT_CMD(cm); 3578233711Sambrisko MFI_VALIDATE_CMD(sc, cm); 3579233711Sambrisko timedout++; 3580233711Sambrisko } 3581162619Sscottl } 3582162619Sscottl } 3583162619Sscottl 3584162619Sscottl#if 0 3585162619Sscottl if (timedout) 3586162619Sscottl MFI_DUMP_CMDS(SC); 3587162619Sscottl#endif 3588162619Sscottl 3589162619Sscottl mtx_unlock(&sc->mfi_io_lock); 3590162619Sscottl 3591162619Sscottl callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, 3592162619Sscottl mfi_timeout, sc); 3593162619Sscottl 3594163398Sscottl if (0) 3595163398Sscottl mfi_dump_all(); 3596162619Sscottl return; 3597162619Sscottl} 3598