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: releng/10.3/sys/dev/mfi/mfi.c 284429 2015-06-15 21:08:08Z ambrisko $"); 55157114Sscottl 56233711Sambrisko#include "opt_compat.h" 57157114Sscottl#include "opt_mfi.h" 58157114Sscottl 59157114Sscottl#include <sys/param.h> 60157114Sscottl#include <sys/systm.h> 61162118Sambrisko#include <sys/sysctl.h> 62157114Sscottl#include <sys/malloc.h> 63157114Sscottl#include <sys/kernel.h> 64158737Sambrisko#include <sys/poll.h> 65158737Sambrisko#include <sys/selinfo.h> 66157114Sscottl#include <sys/bus.h> 67157114Sscottl#include <sys/conf.h> 68157114Sscottl#include <sys/eventhandler.h> 69157114Sscottl#include <sys/rman.h> 70157114Sscottl#include <sys/bus_dma.h> 71157114Sscottl#include <sys/bio.h> 72157114Sscottl#include <sys/ioccom.h> 73158737Sambrisko#include <sys/uio.h> 74158737Sambrisko#include <sys/proc.h> 75163398Sscottl#include <sys/signalvar.h> 76238077Sjhb#include <sys/sysent.h> 77233711Sambrisko#include <sys/taskqueue.h> 78157114Sscottl 79157114Sscottl#include <machine/bus.h> 80157114Sscottl#include <machine/resource.h> 81157114Sscottl 82157114Sscottl#include <dev/mfi/mfireg.h> 83157114Sscottl#include <dev/mfi/mfi_ioctl.h> 84157114Sscottl#include <dev/mfi/mfivar.h> 85233711Sambrisko#include <sys/interrupt.h> 86233711Sambrisko#include <sys/priority.h> 87157114Sscottl 88157114Sscottlstatic int mfi_alloc_commands(struct mfi_softc *); 89157114Sscottlstatic int mfi_comms_init(struct mfi_softc *); 90157114Sscottlstatic int mfi_get_controller_info(struct mfi_softc *); 91158737Sambriskostatic int mfi_get_log_state(struct mfi_softc *, 92159806Sps struct mfi_evt_log_state **); 93180037Sjhbstatic int mfi_parse_entries(struct mfi_softc *, int, int); 94157114Sscottlstatic void mfi_data_cb(void *, bus_dma_segment_t *, int, int); 95157114Sscottlstatic void mfi_startup(void *arg); 96157114Sscottlstatic void mfi_intr(void *arg); 97159811Spsstatic void mfi_ldprobe(struct mfi_softc *sc); 98233711Sambriskostatic void mfi_syspdprobe(struct mfi_softc *sc); 99233711Sambriskostatic void mfi_handle_evt(void *context, int pending); 100158737Sambriskostatic int mfi_aen_register(struct mfi_softc *sc, int seq, int locale); 101158737Sambriskostatic void mfi_aen_complete(struct mfi_command *); 102159811Spsstatic int mfi_add_ld(struct mfi_softc *sc, int); 103159811Spsstatic void mfi_add_ld_complete(struct mfi_command *); 104233711Sambriskostatic int mfi_add_sys_pd(struct mfi_softc *sc, int); 105233711Sambriskostatic void mfi_add_sys_pd_complete(struct mfi_command *); 106157114Sscottlstatic struct mfi_command * mfi_bio_command(struct mfi_softc *); 107157114Sscottlstatic void mfi_bio_complete(struct mfi_command *); 108233711Sambriskostatic struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*); 109233711Sambriskostatic struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*); 110157114Sscottlstatic int mfi_send_frame(struct mfi_softc *, struct mfi_command *); 111247369Ssmhstatic int mfi_std_send_frame(struct mfi_softc *, struct mfi_command *); 112242681Sambriskostatic int mfi_abort(struct mfi_softc *, struct mfi_command **); 113192450Simpstatic int mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, struct thread *); 114162619Sscottlstatic void mfi_timeout(void *); 115178968Sscottlstatic int mfi_user_command(struct mfi_softc *, 116178968Sscottl struct mfi_ioc_passthru *); 117233711Sambriskostatic void mfi_enable_intr_xscale(struct mfi_softc *sc); 118233711Sambriskostatic void mfi_enable_intr_ppc(struct mfi_softc *sc); 119233711Sambriskostatic int32_t mfi_read_fw_status_xscale(struct mfi_softc *sc); 120233711Sambriskostatic int32_t mfi_read_fw_status_ppc(struct mfi_softc *sc); 121233711Sambriskostatic int mfi_check_clear_intr_xscale(struct mfi_softc *sc); 122233711Sambriskostatic int mfi_check_clear_intr_ppc(struct mfi_softc *sc); 123233711Sambriskostatic void mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, 124233711Sambrisko uint32_t frame_cnt); 125233711Sambriskostatic void mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, 126233711Sambrisko uint32_t frame_cnt); 127233711Sambriskostatic int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode); 128233711Sambriskostatic void mfi_config_unlock(struct mfi_softc *sc, int locked); 129233711Sambriskostatic int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm); 130233711Sambriskostatic void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm); 131233711Sambriskostatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm); 132157114Sscottl 133227562SjhbSYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters"); 134162118Sambriskostatic int mfi_event_locale = MFI_EVT_LOCALE_ALL; 135162473SambriskoTUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale); 136247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RWTUN, &mfi_event_locale, 137247369Ssmh 0, "event message locale"); 138162473Sambrisko 139165852Sscottlstatic int mfi_event_class = MFI_EVT_CLASS_INFO; 140162473SambriskoTUNABLE_INT("hw.mfi.event_class", &mfi_event_class); 141247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RWTUN, &mfi_event_class, 142247369Ssmh 0, "event message class"); 143162118Sambrisko 144178968Sscottlstatic int mfi_max_cmds = 128; 145178968SscottlTUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds); 146247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RDTUN, &mfi_max_cmds, 147247369Ssmh 0, "Max commands limit (-1 = controller limit)"); 148178968Sscottl 149233711Sambriskostatic int mfi_detect_jbod_change = 1; 150233711SambriskoTUNABLE_INT("hw.mfi.detect_jbod_change", &mfi_detect_jbod_change); 151247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RWTUN, 152233711Sambrisko &mfi_detect_jbod_change, 0, "Detect a change to a JBOD"); 153233711Sambrisko 154247369Ssmhint mfi_polled_cmd_timeout = MFI_POLL_TIMEOUT_SECS; 155247369SsmhTUNABLE_INT("hw.mfi.polled_cmd_timeout", &mfi_polled_cmd_timeout); 156247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, polled_cmd_timeout, CTLFLAG_RWTUN, 157247369Ssmh &mfi_polled_cmd_timeout, 0, 158247369Ssmh "Polled command timeout - used for firmware flash etc (in seconds)"); 159247369Ssmh 160247426Ssmhstatic int mfi_cmd_timeout = MFI_CMD_TIMEOUT; 161247426SsmhTUNABLE_INT("hw.mfi.cmd_timeout", &mfi_cmd_timeout); 162247426SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, cmd_timeout, CTLFLAG_RWTUN, &mfi_cmd_timeout, 163247426Ssmh 0, "Command timeout (in seconds)"); 164247426Ssmh 165157114Sscottl/* Management interface */ 166157114Sscottlstatic d_open_t mfi_open; 167157114Sscottlstatic d_close_t mfi_close; 168157114Sscottlstatic d_ioctl_t mfi_ioctl; 169158737Sambriskostatic d_poll_t mfi_poll; 170157114Sscottl 171157114Sscottlstatic struct cdevsw mfi_cdevsw = { 172157114Sscottl .d_version = D_VERSION, 173157114Sscottl .d_flags = 0, 174157114Sscottl .d_open = mfi_open, 175157114Sscottl .d_close = mfi_close, 176157114Sscottl .d_ioctl = mfi_ioctl, 177158737Sambrisko .d_poll = mfi_poll, 178157114Sscottl .d_name = "mfi", 179157114Sscottl}; 180157114Sscottl 181157114SscottlMALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver"); 182157114Sscottl 183158737Sambrisko#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH 184233711Sambriskostruct mfi_skinny_dma_info mfi_skinny; 185157114Sscottl 186171980Sscottlstatic void 187171980Sscottlmfi_enable_intr_xscale(struct mfi_softc *sc) 188171980Sscottl{ 189171980Sscottl MFI_WRITE4(sc, MFI_OMSK, 0x01); 190171980Sscottl} 191171980Sscottl 192171980Sscottlstatic void 193171980Sscottlmfi_enable_intr_ppc(struct mfi_softc *sc) 194171980Sscottl{ 195184897Sambrisko if (sc->mfi_flags & MFI_FLAGS_1078) { 196233711Sambrisko MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF); 197184897Sambrisko MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM); 198233711Sambrisko } 199233711Sambrisko else if (sc->mfi_flags & MFI_FLAGS_GEN2) { 200233711Sambrisko MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF); 201184897Sambrisko MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM); 202184897Sambrisko } 203233711Sambrisko else if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 204233711Sambrisko MFI_WRITE4(sc, MFI_OMSK, ~0x00000001); 205233711Sambrisko } 206171980Sscottl} 207171980Sscottl 208171980Sscottlstatic int32_t 209171980Sscottlmfi_read_fw_status_xscale(struct mfi_softc *sc) 210171980Sscottl{ 211171980Sscottl return MFI_READ4(sc, MFI_OMSG0); 212171980Sscottl} 213184897Sambrisko 214171980Sscottlstatic int32_t 215171980Sscottlmfi_read_fw_status_ppc(struct mfi_softc *sc) 216171980Sscottl{ 217171980Sscottl return MFI_READ4(sc, MFI_OSP0); 218171980Sscottl} 219171980Sscottl 220184897Sambriskostatic int 221171980Sscottlmfi_check_clear_intr_xscale(struct mfi_softc *sc) 222171980Sscottl{ 223171980Sscottl int32_t status; 224171980Sscottl 225171980Sscottl status = MFI_READ4(sc, MFI_OSTS); 226171980Sscottl if ((status & MFI_OSTS_INTR_VALID) == 0) 227171980Sscottl return 1; 228171980Sscottl 229171980Sscottl MFI_WRITE4(sc, MFI_OSTS, status); 230171980Sscottl return 0; 231182085Simp} 232171980Sscottl 233184897Sambriskostatic int 234171980Sscottlmfi_check_clear_intr_ppc(struct mfi_softc *sc) 235171980Sscottl{ 236171980Sscottl int32_t status; 237171980Sscottl 238171980Sscottl status = MFI_READ4(sc, MFI_OSTS); 239184897Sambrisko if (sc->mfi_flags & MFI_FLAGS_1078) { 240184897Sambrisko if (!(status & MFI_1078_RM)) { 241184897Sambrisko return 1; 242184897Sambrisko } 243233711Sambrisko } 244233711Sambrisko else if (sc->mfi_flags & MFI_FLAGS_GEN2) { 245184897Sambrisko if (!(status & MFI_GEN2_RM)) { 246184897Sambrisko return 1; 247184897Sambrisko } 248184897Sambrisko } 249233711Sambrisko else if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 250233711Sambrisko if (!(status & MFI_SKINNY_RM)) { 251233711Sambrisko return 1; 252233711Sambrisko } 253233711Sambrisko } 254233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) 255233711Sambrisko MFI_WRITE4(sc, MFI_OSTS, status); 256233711Sambrisko else 257233711Sambrisko MFI_WRITE4(sc, MFI_ODCR0, status); 258171980Sscottl return 0; 259182085Simp} 260171980Sscottl 261184897Sambriskostatic void 262233711Sambriskomfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt) 263171980Sscottl{ 264171980Sscottl MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt); 265171980Sscottl} 266184897Sambrisko 267184897Sambriskostatic void 268233711Sambriskomfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt) 269171980Sscottl{ 270233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 271233711Sambrisko MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt <<1)|1 ); 272233711Sambrisko MFI_WRITE4(sc, MFI_IQPH, 0x00000000); 273233711Sambrisko } else { 274233711Sambrisko MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt <<1)|1 ); 275233711Sambrisko } 276171980Sscottl} 277171980Sscottl 278233711Sambriskoint 279157114Sscottlmfi_transition_firmware(struct mfi_softc *sc) 280157114Sscottl{ 281194851Sscottl uint32_t fw_state, cur_state; 282157114Sscottl int max_wait, i; 283233711Sambrisko uint32_t cur_abs_reg_val = 0; 284233711Sambrisko uint32_t prev_abs_reg_val = 0; 285157114Sscottl 286233711Sambrisko cur_abs_reg_val = sc->mfi_read_fw_status(sc); 287233711Sambrisko fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK; 288157114Sscottl while (fw_state != MFI_FWSTATE_READY) { 289157114Sscottl if (bootverbose) 290157114Sscottl device_printf(sc->mfi_dev, "Waiting for firmware to " 291171980Sscottl "become ready\n"); 292157114Sscottl cur_state = fw_state; 293157114Sscottl switch (fw_state) { 294157114Sscottl case MFI_FWSTATE_FAULT: 295157114Sscottl device_printf(sc->mfi_dev, "Firmware fault\n"); 296157114Sscottl return (ENXIO); 297157114Sscottl case MFI_FWSTATE_WAIT_HANDSHAKE: 298233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 299233711Sambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE); 300233711Sambrisko else 301233711Sambrisko MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE); 302233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 303157114Sscottl break; 304157114Sscottl case MFI_FWSTATE_OPERATIONAL: 305233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 306233711Sambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, 7); 307233711Sambrisko else 308233711Sambrisko MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY); 309233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 310157114Sscottl break; 311157114Sscottl case MFI_FWSTATE_UNDEFINED: 312157114Sscottl case MFI_FWSTATE_BB_INIT: 313233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 314157114Sscottl break; 315233711Sambrisko case MFI_FWSTATE_FW_INIT_2: 316233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 317233711Sambrisko break; 318157114Sscottl case MFI_FWSTATE_FW_INIT: 319157114Sscottl case MFI_FWSTATE_FLUSH_CACHE: 320233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 321157114Sscottl break; 322233711Sambrisko case MFI_FWSTATE_DEVICE_SCAN: 323233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */ 324233711Sambrisko prev_abs_reg_val = cur_abs_reg_val; 325233711Sambrisko break; 326224041Sjhb case MFI_FWSTATE_BOOT_MESSAGE_PENDING: 327233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 328233711Sambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG); 329233711Sambrisko else 330233711Sambrisko MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG); 331233711Sambrisko max_wait = MFI_RESET_WAIT_TIME; 332224041Sjhb break; 333157114Sscottl default: 334233711Sambrisko device_printf(sc->mfi_dev, "Unknown firmware state %#x\n", 335157114Sscottl fw_state); 336157114Sscottl return (ENXIO); 337157114Sscottl } 338157114Sscottl for (i = 0; i < (max_wait * 10); i++) { 339233711Sambrisko cur_abs_reg_val = sc->mfi_read_fw_status(sc); 340233711Sambrisko fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK; 341157114Sscottl if (fw_state == cur_state) 342157114Sscottl DELAY(100000); 343157114Sscottl else 344157114Sscottl break; 345157114Sscottl } 346233711Sambrisko if (fw_state == MFI_FWSTATE_DEVICE_SCAN) { 347233711Sambrisko /* Check the device scanning progress */ 348233711Sambrisko if (prev_abs_reg_val != cur_abs_reg_val) { 349233711Sambrisko continue; 350233711Sambrisko } 351233711Sambrisko } 352157114Sscottl if (fw_state == cur_state) { 353224041Sjhb device_printf(sc->mfi_dev, "Firmware stuck in state " 354157114Sscottl "%#x\n", fw_state); 355157114Sscottl return (ENXIO); 356157114Sscottl } 357157114Sscottl } 358157114Sscottl return (0); 359157114Sscottl} 360157114Sscottl 361157114Sscottlstatic void 362233711Sambriskomfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 363157114Sscottl{ 364233711Sambrisko bus_addr_t *addr; 365157114Sscottl 366157114Sscottl addr = arg; 367157114Sscottl *addr = segs[0].ds_addr; 368157114Sscottl} 369157114Sscottl 370233711Sambrisko 371157114Sscottlint 372157114Sscottlmfi_attach(struct mfi_softc *sc) 373157114Sscottl{ 374157114Sscottl uint32_t status; 375157114Sscottl int error, commsz, framessz, sensesz; 376247369Ssmh int frames, unit, max_fw_sge, max_fw_cmds; 377233711Sambrisko uint32_t tb_mem_size = 0; 378284429Sambrisko struct cdev *dev_t; 379157114Sscottl 380233711Sambrisko if (sc == NULL) 381233711Sambrisko return EINVAL; 382186132Sambrisko 383233711Sambrisko device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n", 384233711Sambrisko MEGASAS_VERSION); 385233711Sambrisko 386157114Sscottl mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF); 387171821Sjhb sx_init(&sc->mfi_config_lock, "MFI config"); 388157114Sscottl TAILQ_INIT(&sc->mfi_ld_tqh); 389233711Sambrisko TAILQ_INIT(&sc->mfi_syspd_tqh); 390242681Sambrisko TAILQ_INIT(&sc->mfi_ld_pend_tqh); 391242681Sambrisko TAILQ_INIT(&sc->mfi_syspd_pend_tqh); 392233711Sambrisko TAILQ_INIT(&sc->mfi_evt_queue); 393233711Sambrisko TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc); 394235014Sambrisko TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc); 395158737Sambrisko TAILQ_INIT(&sc->mfi_aen_pids); 396169611Sscottl TAILQ_INIT(&sc->mfi_cam_ccbq); 397157114Sscottl 398157114Sscottl mfi_initq_free(sc); 399157114Sscottl mfi_initq_ready(sc); 400157114Sscottl mfi_initq_busy(sc); 401157114Sscottl mfi_initq_bio(sc); 402157114Sscottl 403233711Sambrisko sc->adpreset = 0; 404233711Sambrisko sc->last_seq_num = 0; 405233711Sambrisko sc->disableOnlineCtrlReset = 1; 406233711Sambrisko sc->issuepend_done = 1; 407233711Sambrisko sc->hw_crit_error = 0; 408233711Sambrisko 409171980Sscottl if (sc->mfi_flags & MFI_FLAGS_1064R) { 410171980Sscottl sc->mfi_enable_intr = mfi_enable_intr_xscale; 411171980Sscottl sc->mfi_read_fw_status = mfi_read_fw_status_xscale; 412171980Sscottl sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale; 413171980Sscottl sc->mfi_issue_cmd = mfi_issue_cmd_xscale; 414233711Sambrisko } else if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 415233711Sambrisko sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc; 416233711Sambrisko sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc; 417233711Sambrisko sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc; 418233711Sambrisko sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc; 419233711Sambrisko sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc; 420233711Sambrisko sc->mfi_adp_reset = mfi_tbolt_adp_reset; 421233711Sambrisko sc->mfi_tbolt = 1; 422233711Sambrisko TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh); 423233711Sambrisko } else { 424171980Sscottl sc->mfi_enable_intr = mfi_enable_intr_ppc; 425233711Sambrisko sc->mfi_read_fw_status = mfi_read_fw_status_ppc; 426171980Sscottl sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc; 427171980Sscottl sc->mfi_issue_cmd = mfi_issue_cmd_ppc; 428171980Sscottl } 429171980Sscottl 430171980Sscottl 431157114Sscottl /* Before we get too far, see if the firmware is working */ 432157114Sscottl if ((error = mfi_transition_firmware(sc)) != 0) { 433157114Sscottl device_printf(sc->mfi_dev, "Firmware not in READY state, " 434157114Sscottl "error %d\n", error); 435157114Sscottl return (ENXIO); 436157114Sscottl } 437157114Sscottl 438233711Sambrisko /* Start: LSIP200113393 */ 439233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 440233711Sambrisko 1, 0, /* algnmnt, boundary */ 441233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 442233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 443233711Sambrisko NULL, NULL, /* filter, filterarg */ 444233711Sambrisko MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsize */ 445233711Sambrisko 1, /* msegments */ 446233711Sambrisko MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsegsize */ 447233711Sambrisko 0, /* flags */ 448233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 449233711Sambrisko &sc->verbuf_h_dmat)) { 450233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n"); 451233711Sambrisko return (ENOMEM); 452233711Sambrisko } 453233711Sambrisko if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf, 454233711Sambrisko BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) { 455233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n"); 456233711Sambrisko return (ENOMEM); 457233711Sambrisko } 458233711Sambrisko bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t)); 459233711Sambrisko bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap, 460233711Sambrisko sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t), 461233711Sambrisko mfi_addr_cb, &sc->verbuf_h_busaddr, 0); 462233711Sambrisko /* End: LSIP200113393 */ 463233711Sambrisko 464157114Sscottl /* 465157114Sscottl * Get information needed for sizing the contiguous memory for the 466157114Sscottl * frame pool. Size down the sgl parameter since we know that 467157114Sscottl * we will never need more than what's required for MAXPHYS. 468157114Sscottl * It would be nice if these constants were available at runtime 469157114Sscottl * instead of compile time. 470157114Sscottl */ 471171980Sscottl status = sc->mfi_read_fw_status(sc); 472247369Ssmh max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK; 473247369Ssmh if (mfi_max_cmds > 0 && mfi_max_cmds < max_fw_cmds) { 474247369Ssmh device_printf(sc->mfi_dev, "FW MaxCmds = %d, limiting to %d\n", 475247369Ssmh max_fw_cmds, mfi_max_cmds); 476247369Ssmh sc->mfi_max_fw_cmds = mfi_max_cmds; 477247369Ssmh } else { 478247369Ssmh sc->mfi_max_fw_cmds = max_fw_cmds; 479247369Ssmh } 480162458Sscottl max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16; 481195534Sscottl sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1)); 482157114Sscottl 483233711Sambrisko /* ThunderBolt Support get the contiguous memory */ 484233711Sambrisko 485233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 486233711Sambrisko mfi_tbolt_init_globals(sc); 487247369Ssmh device_printf(sc->mfi_dev, "MaxCmd = %d, Drv MaxCmd = %d, " 488247369Ssmh "MaxSgl = %d, state = %#x\n", max_fw_cmds, 489233711Sambrisko sc->mfi_max_fw_cmds, sc->mfi_max_sge, status); 490233711Sambrisko tb_mem_size = mfi_tbolt_get_memory_requirement(sc); 491233711Sambrisko 492233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 493233711Sambrisko 1, 0, /* algnmnt, boundary */ 494233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 495233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 496233711Sambrisko NULL, NULL, /* filter, filterarg */ 497233711Sambrisko tb_mem_size, /* maxsize */ 498233711Sambrisko 1, /* msegments */ 499233711Sambrisko tb_mem_size, /* maxsegsize */ 500233711Sambrisko 0, /* flags */ 501233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 502233711Sambrisko &sc->mfi_tb_dmat)) { 503233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n"); 504233711Sambrisko return (ENOMEM); 505233711Sambrisko } 506233711Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool, 507233711Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) { 508233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 509233711Sambrisko return (ENOMEM); 510233711Sambrisko } 511233711Sambrisko bzero(sc->request_message_pool, tb_mem_size); 512233711Sambrisko bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap, 513233711Sambrisko sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0); 514233711Sambrisko 515233711Sambrisko /* For ThunderBolt memory init */ 516233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 517233711Sambrisko 0x100, 0, /* alignmnt, boundary */ 518233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 519233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 520233711Sambrisko NULL, NULL, /* filter, filterarg */ 521233711Sambrisko MFI_FRAME_SIZE, /* maxsize */ 522233711Sambrisko 1, /* msegments */ 523233711Sambrisko MFI_FRAME_SIZE, /* maxsegsize */ 524233711Sambrisko 0, /* flags */ 525233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 526233711Sambrisko &sc->mfi_tb_init_dmat)) { 527247369Ssmh device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n"); 528247369Ssmh return (ENOMEM); 529233711Sambrisko } 530233711Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init, 531233711Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) { 532233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate init memory\n"); 533233711Sambrisko return (ENOMEM); 534233711Sambrisko } 535233711Sambrisko bzero(sc->mfi_tb_init, MFI_FRAME_SIZE); 536233711Sambrisko bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap, 537233711Sambrisko sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb, 538233711Sambrisko &sc->mfi_tb_init_busaddr, 0); 539233711Sambrisko if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool, 540233711Sambrisko tb_mem_size)) { 541233711Sambrisko device_printf(sc->mfi_dev, 542233711Sambrisko "Thunderbolt pool preparation error\n"); 543233711Sambrisko return 0; 544233711Sambrisko } 545233711Sambrisko 546233711Sambrisko /* 547233711Sambrisko Allocate DMA memory mapping for MPI2 IOC Init descriptor, 548233711Sambrisko we are taking it diffrent from what we have allocated for Request 549233711Sambrisko and reply descriptors to avoid confusion later 550233711Sambrisko */ 551233711Sambrisko tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST); 552233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 553233711Sambrisko 1, 0, /* algnmnt, boundary */ 554233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 555233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 556233711Sambrisko NULL, NULL, /* filter, filterarg */ 557233711Sambrisko tb_mem_size, /* maxsize */ 558233711Sambrisko 1, /* msegments */ 559233711Sambrisko tb_mem_size, /* maxsegsize */ 560233711Sambrisko 0, /* flags */ 561233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 562233711Sambrisko &sc->mfi_tb_ioc_init_dmat)) { 563233711Sambrisko device_printf(sc->mfi_dev, 564233711Sambrisko "Cannot allocate comms DMA tag\n"); 565233711Sambrisko return (ENOMEM); 566233711Sambrisko } 567233711Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat, 568233711Sambrisko (void **)&sc->mfi_tb_ioc_init_desc, 569233711Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) { 570233711Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 571233711Sambrisko return (ENOMEM); 572233711Sambrisko } 573233711Sambrisko bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size); 574233711Sambrisko bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap, 575233711Sambrisko sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb, 576233711Sambrisko &sc->mfi_tb_ioc_init_busaddr, 0); 577233711Sambrisko } 578157114Sscottl /* 579157114Sscottl * Create the dma tag for data buffers. Used both for block I/O 580157114Sscottl * and for various internal data queries. 581157114Sscottl */ 582157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 583157114Sscottl 1, 0, /* algnmnt, boundary */ 584157114Sscottl BUS_SPACE_MAXADDR, /* lowaddr */ 585157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 586157114Sscottl NULL, NULL, /* filter, filterarg */ 587157114Sscottl BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 588162458Sscottl sc->mfi_max_sge, /* nsegments */ 589157114Sscottl BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 590157114Sscottl BUS_DMA_ALLOCNOW, /* flags */ 591157114Sscottl busdma_lock_mutex, /* lockfunc */ 592157114Sscottl &sc->mfi_io_lock, /* lockfuncarg */ 593157114Sscottl &sc->mfi_buffer_dmat)) { 594157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n"); 595157114Sscottl return (ENOMEM); 596157114Sscottl } 597157114Sscottl 598157114Sscottl /* 599157114Sscottl * Allocate DMA memory for the comms queues. Keep it under 4GB for 600157114Sscottl * efficiency. The mfi_hwcomms struct includes space for 1 reply queue 601157114Sscottl * entry, so the calculated size here will be will be 1 more than 602157114Sscottl * mfi_max_fw_cmds. This is apparently a requirement of the hardware. 603157114Sscottl */ 604157114Sscottl commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) + 605157114Sscottl sizeof(struct mfi_hwcomms); 606157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 607157114Sscottl 1, 0, /* algnmnt, boundary */ 608157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 609157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 610157114Sscottl NULL, NULL, /* filter, filterarg */ 611157114Sscottl commsz, /* maxsize */ 612157114Sscottl 1, /* msegments */ 613157114Sscottl commsz, /* maxsegsize */ 614157114Sscottl 0, /* flags */ 615157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 616157114Sscottl &sc->mfi_comms_dmat)) { 617157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n"); 618157114Sscottl return (ENOMEM); 619157114Sscottl } 620157114Sscottl if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms, 621157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) { 622157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 623157114Sscottl return (ENOMEM); 624157114Sscottl } 625157114Sscottl bzero(sc->mfi_comms, commsz); 626157114Sscottl bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap, 627233711Sambrisko sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0); 628157114Sscottl /* 629157114Sscottl * Allocate DMA memory for the command frames. Keep them in the 630162458Sscottl * lower 4GB for efficiency. Calculate the size of the commands at 631162458Sscottl * the same time; each command is one 64 byte frame plus a set of 632162458Sscottl * additional frames for holding sg lists or other data. 633157114Sscottl * The assumption here is that the SG list will start at the second 634162458Sscottl * frame and not use the unused bytes in the first frame. While this 635162458Sscottl * isn't technically correct, it simplifies the calculation and allows 636162458Sscottl * for command frames that might be larger than an mfi_io_frame. 637157114Sscottl */ 638157114Sscottl if (sizeof(bus_addr_t) == 8) { 639162458Sscottl sc->mfi_sge_size = sizeof(struct mfi_sg64); 640157114Sscottl sc->mfi_flags |= MFI_FLAGS_SG64; 641157114Sscottl } else { 642162458Sscottl sc->mfi_sge_size = sizeof(struct mfi_sg32); 643157114Sscottl } 644233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) 645233711Sambrisko sc->mfi_sge_size = sizeof(struct mfi_sg_skinny); 646162458Sscottl frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2; 647162458Sscottl sc->mfi_cmd_size = frames * MFI_FRAME_SIZE; 648162458Sscottl framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds; 649157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 650157114Sscottl 64, 0, /* algnmnt, boundary */ 651157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 652157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 653157114Sscottl NULL, NULL, /* filter, filterarg */ 654157114Sscottl framessz, /* maxsize */ 655157114Sscottl 1, /* nsegments */ 656157114Sscottl framessz, /* maxsegsize */ 657157114Sscottl 0, /* flags */ 658157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 659157114Sscottl &sc->mfi_frames_dmat)) { 660157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n"); 661157114Sscottl return (ENOMEM); 662157114Sscottl } 663157114Sscottl if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames, 664157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) { 665157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate frames memory\n"); 666157114Sscottl return (ENOMEM); 667157114Sscottl } 668157114Sscottl bzero(sc->mfi_frames, framessz); 669157114Sscottl bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap, 670233711Sambrisko sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0); 671157114Sscottl /* 672157114Sscottl * Allocate DMA memory for the frame sense data. Keep them in the 673157114Sscottl * lower 4GB for efficiency 674157114Sscottl */ 675157114Sscottl sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN; 676157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 677157114Sscottl 4, 0, /* algnmnt, boundary */ 678157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 679157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 680157114Sscottl NULL, NULL, /* filter, filterarg */ 681157114Sscottl sensesz, /* maxsize */ 682157114Sscottl 1, /* nsegments */ 683157114Sscottl sensesz, /* maxsegsize */ 684157114Sscottl 0, /* flags */ 685157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 686157114Sscottl &sc->mfi_sense_dmat)) { 687157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n"); 688157114Sscottl return (ENOMEM); 689157114Sscottl } 690157114Sscottl if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense, 691157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) { 692157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate sense memory\n"); 693157114Sscottl return (ENOMEM); 694157114Sscottl } 695157114Sscottl bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap, 696233711Sambrisko sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0); 697157114Sscottl if ((error = mfi_alloc_commands(sc)) != 0) 698157114Sscottl return (error); 699157114Sscottl 700233711Sambrisko /* Before moving the FW to operational state, check whether 701233711Sambrisko * hostmemory is required by the FW or not 702233711Sambrisko */ 703157114Sscottl 704233711Sambrisko /* ThunderBolt MFI_IOC2 INIT */ 705233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 706233711Sambrisko sc->mfi_disable_intr(sc); 707247369Ssmh mtx_lock(&sc->mfi_io_lock); 708233711Sambrisko if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) { 709233711Sambrisko device_printf(sc->mfi_dev, 710233711Sambrisko "TB Init has failed with error %d\n",error); 711247369Ssmh mtx_unlock(&sc->mfi_io_lock); 712233711Sambrisko return error; 713233711Sambrisko } 714247369Ssmh mtx_unlock(&sc->mfi_io_lock); 715157114Sscottl 716233711Sambrisko if ((error = mfi_tbolt_alloc_cmd(sc)) != 0) 717233711Sambrisko return error; 718233711Sambrisko if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, 719233711Sambrisko INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc, 720233711Sambrisko &sc->mfi_intr)) { 721233711Sambrisko device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); 722233711Sambrisko return (EINVAL); 723233711Sambrisko } 724242681Sambrisko sc->mfi_intr_ptr = mfi_intr_tbolt; 725233711Sambrisko sc->mfi_enable_intr(sc); 726233711Sambrisko } else { 727233711Sambrisko if ((error = mfi_comms_init(sc)) != 0) 728233711Sambrisko return (error); 729157114Sscottl 730233711Sambrisko if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, 731233711Sambrisko INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) { 732233711Sambrisko device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); 733233711Sambrisko return (EINVAL); 734233711Sambrisko } 735242681Sambrisko sc->mfi_intr_ptr = mfi_intr; 736233711Sambrisko sc->mfi_enable_intr(sc); 737157114Sscottl } 738233711Sambrisko if ((error = mfi_get_controller_info(sc)) != 0) 739233711Sambrisko return (error); 740233711Sambrisko sc->disableOnlineCtrlReset = 0; 741157114Sscottl 742157114Sscottl /* Register a config hook to probe the bus for arrays */ 743157114Sscottl sc->mfi_ich.ich_func = mfi_startup; 744157114Sscottl sc->mfi_ich.ich_arg = sc; 745157114Sscottl if (config_intrhook_establish(&sc->mfi_ich) != 0) { 746157114Sscottl device_printf(sc->mfi_dev, "Cannot establish configuration " 747157114Sscottl "hook\n"); 748157114Sscottl return (EINVAL); 749157114Sscottl } 750247369Ssmh mtx_lock(&sc->mfi_io_lock); 751247369Ssmh if ((error = mfi_aen_setup(sc, 0), 0) != 0) { 752247369Ssmh mtx_unlock(&sc->mfi_io_lock); 753233711Sambrisko return (error); 754247369Ssmh } 755247369Ssmh mtx_unlock(&sc->mfi_io_lock); 756157114Sscottl 757157114Sscottl /* 758157114Sscottl * Register a shutdown handler. 759157114Sscottl */ 760157114Sscottl if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown, 761157114Sscottl sc, SHUTDOWN_PRI_DEFAULT)) == NULL) { 762157114Sscottl device_printf(sc->mfi_dev, "Warning: shutdown event " 763157114Sscottl "registration failed\n"); 764157114Sscottl } 765157114Sscottl 766157114Sscottl /* 767157114Sscottl * Create the control device for doing management 768157114Sscottl */ 769157114Sscottl unit = device_get_unit(sc->mfi_dev); 770157114Sscottl sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR, 771157114Sscottl 0640, "mfi%d", unit); 772158737Sambrisko if (unit == 0) 773284429Sambrisko make_dev_alias_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &dev_t, 774284429Sambrisko sc->mfi_cdev, "%s", "megaraid_sas_ioctl_node"); 775157114Sscottl if (sc->mfi_cdev != NULL) 776157114Sscottl sc->mfi_cdev->si_drv1 = sc; 777171821Sjhb SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev), 778171821Sjhb SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), 779171821Sjhb OID_AUTO, "delete_busy_volumes", CTLFLAG_RW, 780171821Sjhb &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes"); 781171821Sjhb SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev), 782171821Sjhb SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), 783171821Sjhb OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW, 784171821Sjhb &sc->mfi_keep_deleted_volumes, 0, 785171821Sjhb "Don't detach the mfid device for a busy volume that is deleted"); 786157114Sscottl 787169611Sscottl device_add_child(sc->mfi_dev, "mfip", -1); 788169611Sscottl bus_generic_attach(sc->mfi_dev); 789169611Sscottl 790162619Sscottl /* Start the timeout watchdog */ 791178250Skris callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE); 792247426Ssmh callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz, 793162619Sscottl mfi_timeout, sc); 794162619Sscottl 795235014Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 796247369Ssmh mtx_lock(&sc->mfi_io_lock); 797235014Sambrisko mfi_tbolt_sync_map_info(sc); 798247369Ssmh mtx_unlock(&sc->mfi_io_lock); 799235014Sambrisko } 800235014Sambrisko 801157114Sscottl return (0); 802157114Sscottl} 803157114Sscottl 804157114Sscottlstatic int 805157114Sscottlmfi_alloc_commands(struct mfi_softc *sc) 806157114Sscottl{ 807157114Sscottl struct mfi_command *cm; 808247369Ssmh int i, j; 809157114Sscottl 810157114Sscottl /* 811157114Sscottl * XXX Should we allocate all the commands up front, or allocate on 812157114Sscottl * demand later like 'aac' does? 813157114Sscottl */ 814247369Ssmh sc->mfi_commands = malloc(sizeof(sc->mfi_commands[0]) * 815247369Ssmh sc->mfi_max_fw_cmds, M_MFIBUF, M_WAITOK | M_ZERO); 816178968Sscottl 817247369Ssmh for (i = 0; i < sc->mfi_max_fw_cmds; i++) { 818157114Sscottl cm = &sc->mfi_commands[i]; 819158737Sambrisko cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames + 820162458Sscottl sc->mfi_cmd_size * i); 821157114Sscottl cm->cm_frame_busaddr = sc->mfi_frames_busaddr + 822162458Sscottl sc->mfi_cmd_size * i; 823157114Sscottl cm->cm_frame->header.context = i; 824157114Sscottl cm->cm_sense = &sc->mfi_sense[i]; 825157114Sscottl cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i; 826157114Sscottl cm->cm_sc = sc; 827162619Sscottl cm->cm_index = i; 828157114Sscottl if (bus_dmamap_create(sc->mfi_buffer_dmat, 0, 829233711Sambrisko &cm->cm_dmamap) == 0) { 830233711Sambrisko mtx_lock(&sc->mfi_io_lock); 831157114Sscottl mfi_release_command(cm); 832233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 833247369Ssmh } else { 834247369Ssmh device_printf(sc->mfi_dev, "Failed to allocate %d " 835247369Ssmh "command blocks, only allocated %d\n", 836247369Ssmh sc->mfi_max_fw_cmds, i - 1); 837247369Ssmh for (j = 0; j < i; j++) { 838247369Ssmh cm = &sc->mfi_commands[i]; 839247369Ssmh bus_dmamap_destroy(sc->mfi_buffer_dmat, 840247369Ssmh cm->cm_dmamap); 841247369Ssmh } 842247369Ssmh free(sc->mfi_commands, M_MFIBUF); 843247369Ssmh sc->mfi_commands = NULL; 844247369Ssmh 845247369Ssmh return (ENOMEM); 846233711Sambrisko } 847157114Sscottl } 848157114Sscottl 849157114Sscottl return (0); 850157114Sscottl} 851157114Sscottl 852169611Sscottlvoid 853157114Sscottlmfi_release_command(struct mfi_command *cm) 854157114Sscottl{ 855163398Sscottl struct mfi_frame_header *hdr; 856157114Sscottl uint32_t *hdr_data; 857157114Sscottl 858233711Sambrisko mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED); 859233711Sambrisko 860157114Sscottl /* 861157114Sscottl * Zero out the important fields of the frame, but make sure the 862165727Sscottl * context field is preserved. For efficiency, handle the fields 863165727Sscottl * as 32 bit words. Clear out the first S/G entry too for safety. 864157114Sscottl */ 865163398Sscottl hdr = &cm->cm_frame->header; 866175897Sambrisko if (cm->cm_data != NULL && hdr->sg_count) { 867163398Sscottl cm->cm_sg->sg32[0].len = 0; 868163398Sscottl cm->cm_sg->sg32[0].addr = 0; 869163398Sscottl } 870165727Sscottl 871247369Ssmh /* 872247369Ssmh * Command may be on other queues e.g. busy queue depending on the 873247369Ssmh * flow of a previous call to mfi_mapcmd, so ensure its dequeued 874247369Ssmh * properly 875247369Ssmh */ 876247369Ssmh if ((cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0) 877247369Ssmh mfi_remove_busy(cm); 878247369Ssmh if ((cm->cm_flags & MFI_ON_MFIQ_READY) != 0) 879247369Ssmh mfi_remove_ready(cm); 880247369Ssmh 881247369Ssmh /* We're not expecting it to be on any other queue but check */ 882247369Ssmh if ((cm->cm_flags & MFI_ON_MFIQ_MASK) != 0) { 883247369Ssmh panic("Command %p is still on another queue, flags = %#x", 884247369Ssmh cm, cm->cm_flags); 885247369Ssmh } 886247369Ssmh 887247369Ssmh /* tbolt cleanup */ 888247369Ssmh if ((cm->cm_flags & MFI_CMD_TBOLT) != 0) { 889247369Ssmh mfi_tbolt_return_cmd(cm->cm_sc, 890247369Ssmh cm->cm_sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames - 1], 891247369Ssmh cm); 892247369Ssmh } 893247369Ssmh 894165727Sscottl hdr_data = (uint32_t *)cm->cm_frame; 895165727Sscottl hdr_data[0] = 0; /* cmd, sense_len, cmd_status, scsi_status */ 896165727Sscottl hdr_data[1] = 0; /* target_id, lun_id, cdb_len, sg_count */ 897165727Sscottl hdr_data[4] = 0; /* flags, timeout */ 898165727Sscottl hdr_data[5] = 0; /* data_len */ 899165727Sscottl 900157114Sscottl cm->cm_extra_frames = 0; 901157114Sscottl cm->cm_flags = 0; 902157114Sscottl cm->cm_complete = NULL; 903157114Sscottl cm->cm_private = NULL; 904169611Sscottl cm->cm_data = NULL; 905157114Sscottl cm->cm_sg = 0; 906157114Sscottl cm->cm_total_frame_size = 0; 907233711Sambrisko cm->retry_for_fw_reset = 0; 908163398Sscottl 909157114Sscottl mfi_enqueue_free(cm); 910157114Sscottl} 911157114Sscottl 912235014Sambriskoint 913233711Sambriskomfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, 914233711Sambrisko uint32_t opcode, void **bufp, size_t bufsize) 915159806Sps{ 916159806Sps struct mfi_command *cm; 917159806Sps struct mfi_dcmd_frame *dcmd; 918159806Sps void *buf = NULL; 919233711Sambrisko uint32_t context = 0; 920233711Sambrisko 921159806Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 922233711Sambrisko 923159806Sps cm = mfi_dequeue_free(sc); 924159806Sps if (cm == NULL) 925159806Sps return (EBUSY); 926159806Sps 927233711Sambrisko /* Zero out the MFI frame */ 928233711Sambrisko context = cm->cm_frame->header.context; 929233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 930233711Sambrisko cm->cm_frame->header.context = context; 931233711Sambrisko 932159806Sps if ((bufsize > 0) && (bufp != NULL)) { 933159806Sps if (*bufp == NULL) { 934159806Sps buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO); 935159806Sps if (buf == NULL) { 936159806Sps mfi_release_command(cm); 937159806Sps return (ENOMEM); 938159806Sps } 939159806Sps *bufp = buf; 940159806Sps } else { 941159806Sps buf = *bufp; 942159806Sps } 943159806Sps } 944159806Sps 945159806Sps dcmd = &cm->cm_frame->dcmd; 946159806Sps bzero(dcmd->mbox, MFI_MBOX_SIZE); 947159806Sps dcmd->header.cmd = MFI_CMD_DCMD; 948159806Sps dcmd->header.timeout = 0; 949159806Sps dcmd->header.flags = 0; 950159806Sps dcmd->header.data_len = bufsize; 951233711Sambrisko dcmd->header.scsi_status = 0; 952159806Sps dcmd->opcode = opcode; 953159806Sps cm->cm_sg = &dcmd->sgl; 954159806Sps cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 955159806Sps cm->cm_flags = 0; 956159806Sps cm->cm_data = buf; 957159806Sps cm->cm_private = buf; 958159806Sps cm->cm_len = bufsize; 959159806Sps 960159806Sps *cmp = cm; 961159806Sps if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL)) 962159806Sps *bufp = buf; 963159806Sps return (0); 964159806Sps} 965159806Sps 966159806Spsstatic int 967157114Sscottlmfi_comms_init(struct mfi_softc *sc) 968157114Sscottl{ 969157114Sscottl struct mfi_command *cm; 970157114Sscottl struct mfi_init_frame *init; 971157114Sscottl struct mfi_init_qinfo *qinfo; 972157114Sscottl int error; 973233711Sambrisko uint32_t context = 0; 974157114Sscottl 975163398Sscottl mtx_lock(&sc->mfi_io_lock); 976247369Ssmh if ((cm = mfi_dequeue_free(sc)) == NULL) { 977247369Ssmh mtx_unlock(&sc->mfi_io_lock); 978157114Sscottl return (EBUSY); 979247369Ssmh } 980157114Sscottl 981233711Sambrisko /* Zero out the MFI frame */ 982233711Sambrisko context = cm->cm_frame->header.context; 983233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 984233711Sambrisko cm->cm_frame->header.context = context; 985233711Sambrisko 986157114Sscottl /* 987157114Sscottl * Abuse the SG list area of the frame to hold the init_qinfo 988157114Sscottl * object; 989157114Sscottl */ 990157114Sscottl init = &cm->cm_frame->init; 991157114Sscottl qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE); 992157114Sscottl 993157114Sscottl bzero(qinfo, sizeof(struct mfi_init_qinfo)); 994157114Sscottl qinfo->rq_entries = sc->mfi_max_fw_cmds + 1; 995157114Sscottl qinfo->rq_addr_lo = sc->mfi_comms_busaddr + 996157114Sscottl offsetof(struct mfi_hwcomms, hw_reply_q); 997157114Sscottl qinfo->pi_addr_lo = sc->mfi_comms_busaddr + 998157114Sscottl offsetof(struct mfi_hwcomms, hw_pi); 999157114Sscottl qinfo->ci_addr_lo = sc->mfi_comms_busaddr + 1000157114Sscottl offsetof(struct mfi_hwcomms, hw_ci); 1001157114Sscottl 1002157114Sscottl init->header.cmd = MFI_CMD_INIT; 1003157114Sscottl init->header.data_len = sizeof(struct mfi_init_qinfo); 1004157114Sscottl init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE; 1005164375Sscottl cm->cm_data = NULL; 1006164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 1007157114Sscottl 1008247369Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) 1009157114Sscottl device_printf(sc->mfi_dev, "failed to send init command\n"); 1010157114Sscottl mfi_release_command(cm); 1011163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1012157114Sscottl 1013247369Ssmh return (error); 1014157114Sscottl} 1015157114Sscottl 1016157114Sscottlstatic int 1017157114Sscottlmfi_get_controller_info(struct mfi_softc *sc) 1018157114Sscottl{ 1019159806Sps struct mfi_command *cm = NULL; 1020159806Sps struct mfi_ctrl_info *ci = NULL; 1021157114Sscottl uint32_t max_sectors_1, max_sectors_2; 1022157114Sscottl int error; 1023157114Sscottl 1024159806Sps mtx_lock(&sc->mfi_io_lock); 1025159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO, 1026159806Sps (void **)&ci, sizeof(*ci)); 1027159806Sps if (error) 1028159806Sps goto out; 1029157114Sscottl cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1030157114Sscottl 1031157114Sscottl if ((error = mfi_mapcmd(sc, cm)) != 0) { 1032157114Sscottl device_printf(sc->mfi_dev, "Failed to get controller info\n"); 1033162458Sscottl sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE / 1034157114Sscottl MFI_SECTOR_LEN; 1035159806Sps error = 0; 1036159806Sps goto out; 1037157114Sscottl } 1038157114Sscottl 1039157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1040157114Sscottl BUS_DMASYNC_POSTREAD); 1041157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1042157114Sscottl 1043233711Sambrisko max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io; 1044157114Sscottl max_sectors_2 = ci->max_request_size; 1045157114Sscottl sc->mfi_max_io = min(max_sectors_1, max_sectors_2); 1046233711Sambrisko sc->disableOnlineCtrlReset = 1047233711Sambrisko ci->properties.OnOffProperties.disableOnlineCtrlReset; 1048157114Sscottl 1049159806Spsout: 1050159806Sps if (ci) 1051159806Sps free(ci, M_MFIBUF); 1052159806Sps if (cm) 1053159806Sps mfi_release_command(cm); 1054159806Sps mtx_unlock(&sc->mfi_io_lock); 1055157114Sscottl return (error); 1056157114Sscottl} 1057157114Sscottl 1058157114Sscottlstatic int 1059159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state) 1060158737Sambrisko{ 1061159812Sps struct mfi_command *cm = NULL; 1062158737Sambrisko int error; 1063158737Sambrisko 1064247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1065159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO, 1066159806Sps (void **)log_state, sizeof(**log_state)); 1067159806Sps if (error) 1068159806Sps goto out; 1069159810Sps cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1070158737Sambrisko 1071158737Sambrisko if ((error = mfi_mapcmd(sc, cm)) != 0) { 1072159802Sps device_printf(sc->mfi_dev, "Failed to get log state\n"); 1073159806Sps goto out; 1074158737Sambrisko } 1075158737Sambrisko 1076158737Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1077158737Sambrisko BUS_DMASYNC_POSTREAD); 1078158737Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1079158737Sambrisko 1080159806Spsout: 1081159812Sps if (cm) 1082159812Sps mfi_release_command(cm); 1083158737Sambrisko 1084158737Sambrisko return (error); 1085158737Sambrisko} 1086158737Sambrisko 1087233711Sambriskoint 1088158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start) 1089158737Sambrisko{ 1090159806Sps struct mfi_evt_log_state *log_state = NULL; 1091158737Sambrisko union mfi_evt class_locale; 1092158737Sambrisko int error = 0; 1093158737Sambrisko uint32_t seq; 1094158737Sambrisko 1095247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1096247369Ssmh 1097158737Sambrisko class_locale.members.reserved = 0; 1098162118Sambrisko class_locale.members.locale = mfi_event_locale; 1099222589Semaste class_locale.members.evt_class = mfi_event_class; 1100158737Sambrisko 1101158737Sambrisko if (seq_start == 0) { 1102247369Ssmh if ((error = mfi_get_log_state(sc, &log_state)) != 0) 1103247369Ssmh goto out; 1104233711Sambrisko sc->mfi_boot_seq_num = log_state->boot_seq_num; 1105180037Sjhb 1106180037Sjhb /* 1107180037Sjhb * Walk through any events that fired since the last 1108180037Sjhb * shutdown. 1109180037Sjhb */ 1110247369Ssmh if ((error = mfi_parse_entries(sc, log_state->shutdown_seq_num, 1111247369Ssmh log_state->newest_seq_num)) != 0) 1112247369Ssmh goto out; 1113180037Sjhb seq = log_state->newest_seq_num; 1114158737Sambrisko } else 1115158737Sambrisko seq = seq_start; 1116247369Ssmh error = mfi_aen_register(sc, seq, class_locale.word); 1117247369Ssmhout: 1118159806Sps free(log_state, M_MFIBUF); 1119158737Sambrisko 1120247369Ssmh return (error); 1121158737Sambrisko} 1122158737Sambrisko 1123233711Sambriskoint 1124159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm) 1125159811Sps{ 1126159811Sps 1127159811Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1128159811Sps cm->cm_complete = NULL; 1129159811Sps 1130170284Sambrisko /* 1131170284Sambrisko * MegaCli can issue a DCMD of 0. In this case do nothing 1132170284Sambrisko * and return 0 to it as status 1133170284Sambrisko */ 1134170284Sambrisko if (cm->cm_frame->dcmd.opcode == 0) { 1135170284Sambrisko cm->cm_frame->header.cmd_status = MFI_STAT_OK; 1136170284Sambrisko cm->cm_error = 0; 1137170284Sambrisko return (cm->cm_error); 1138170284Sambrisko } 1139159811Sps mfi_enqueue_ready(cm); 1140159811Sps mfi_startio(sc); 1141170284Sambrisko if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0) 1142170284Sambrisko msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0); 1143170284Sambrisko return (cm->cm_error); 1144159811Sps} 1145159811Sps 1146157114Sscottlvoid 1147157114Sscottlmfi_free(struct mfi_softc *sc) 1148157114Sscottl{ 1149157114Sscottl struct mfi_command *cm; 1150157114Sscottl int i; 1151157114Sscottl 1152162619Sscottl callout_drain(&sc->mfi_watchdog_callout); 1153162619Sscottl 1154157114Sscottl if (sc->mfi_cdev != NULL) 1155157114Sscottl destroy_dev(sc->mfi_cdev); 1156157114Sscottl 1157247369Ssmh if (sc->mfi_commands != NULL) { 1158247369Ssmh for (i = 0; i < sc->mfi_max_fw_cmds; i++) { 1159157114Sscottl cm = &sc->mfi_commands[i]; 1160157114Sscottl bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap); 1161157114Sscottl } 1162157114Sscottl free(sc->mfi_commands, M_MFIBUF); 1163247369Ssmh sc->mfi_commands = NULL; 1164157114Sscottl } 1165157114Sscottl 1166157114Sscottl if (sc->mfi_intr) 1167157114Sscottl bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr); 1168157114Sscottl if (sc->mfi_irq != NULL) 1169157114Sscottl bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid, 1170157114Sscottl sc->mfi_irq); 1171157114Sscottl 1172157114Sscottl if (sc->mfi_sense_busaddr != 0) 1173157114Sscottl bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap); 1174157114Sscottl if (sc->mfi_sense != NULL) 1175157114Sscottl bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense, 1176157114Sscottl sc->mfi_sense_dmamap); 1177157114Sscottl if (sc->mfi_sense_dmat != NULL) 1178157114Sscottl bus_dma_tag_destroy(sc->mfi_sense_dmat); 1179157114Sscottl 1180157114Sscottl if (sc->mfi_frames_busaddr != 0) 1181157114Sscottl bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap); 1182157114Sscottl if (sc->mfi_frames != NULL) 1183157114Sscottl bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames, 1184157114Sscottl sc->mfi_frames_dmamap); 1185157114Sscottl if (sc->mfi_frames_dmat != NULL) 1186157114Sscottl bus_dma_tag_destroy(sc->mfi_frames_dmat); 1187157114Sscottl 1188157114Sscottl if (sc->mfi_comms_busaddr != 0) 1189157114Sscottl bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap); 1190157114Sscottl if (sc->mfi_comms != NULL) 1191157114Sscottl bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms, 1192157114Sscottl sc->mfi_comms_dmamap); 1193157114Sscottl if (sc->mfi_comms_dmat != NULL) 1194157114Sscottl bus_dma_tag_destroy(sc->mfi_comms_dmat); 1195157114Sscottl 1196233711Sambrisko /* ThunderBolt contiguous memory free here */ 1197233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 1198233711Sambrisko if (sc->mfi_tb_busaddr != 0) 1199233711Sambrisko bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap); 1200233711Sambrisko if (sc->request_message_pool != NULL) 1201233711Sambrisko bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool, 1202233711Sambrisko sc->mfi_tb_dmamap); 1203233711Sambrisko if (sc->mfi_tb_dmat != NULL) 1204233711Sambrisko bus_dma_tag_destroy(sc->mfi_tb_dmat); 1205233711Sambrisko 1206233711Sambrisko /* Version buffer memory free */ 1207233711Sambrisko /* Start LSIP200113393 */ 1208233711Sambrisko if (sc->verbuf_h_busaddr != 0) 1209233711Sambrisko bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap); 1210233711Sambrisko if (sc->verbuf != NULL) 1211233711Sambrisko bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf, 1212233711Sambrisko sc->verbuf_h_dmamap); 1213233711Sambrisko if (sc->verbuf_h_dmat != NULL) 1214233711Sambrisko bus_dma_tag_destroy(sc->verbuf_h_dmat); 1215233711Sambrisko 1216233711Sambrisko /* End LSIP200113393 */ 1217233711Sambrisko /* ThunderBolt INIT packet memory Free */ 1218233711Sambrisko if (sc->mfi_tb_init_busaddr != 0) 1219247369Ssmh bus_dmamap_unload(sc->mfi_tb_init_dmat, 1220247369Ssmh sc->mfi_tb_init_dmamap); 1221233711Sambrisko if (sc->mfi_tb_init != NULL) 1222233711Sambrisko bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init, 1223233711Sambrisko sc->mfi_tb_init_dmamap); 1224233711Sambrisko if (sc->mfi_tb_init_dmat != NULL) 1225233711Sambrisko bus_dma_tag_destroy(sc->mfi_tb_init_dmat); 1226233711Sambrisko 1227233711Sambrisko /* ThunderBolt IOC Init Desc memory free here */ 1228233711Sambrisko if (sc->mfi_tb_ioc_init_busaddr != 0) 1229233711Sambrisko bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat, 1230233711Sambrisko sc->mfi_tb_ioc_init_dmamap); 1231233711Sambrisko if (sc->mfi_tb_ioc_init_desc != NULL) 1232233711Sambrisko bus_dmamem_free(sc->mfi_tb_ioc_init_dmat, 1233233711Sambrisko sc->mfi_tb_ioc_init_desc, 1234233711Sambrisko sc->mfi_tb_ioc_init_dmamap); 1235233711Sambrisko if (sc->mfi_tb_ioc_init_dmat != NULL) 1236233711Sambrisko bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat); 1237247369Ssmh if (sc->mfi_cmd_pool_tbolt != NULL) { 1238247369Ssmh for (int i = 0; i < sc->mfi_max_fw_cmds; i++) { 1239233711Sambrisko if (sc->mfi_cmd_pool_tbolt[i] != NULL) { 1240233711Sambrisko free(sc->mfi_cmd_pool_tbolt[i], 1241233711Sambrisko M_MFIBUF); 1242233711Sambrisko sc->mfi_cmd_pool_tbolt[i] = NULL; 1243233711Sambrisko } 1244233711Sambrisko } 1245233711Sambrisko free(sc->mfi_cmd_pool_tbolt, M_MFIBUF); 1246233711Sambrisko sc->mfi_cmd_pool_tbolt = NULL; 1247233711Sambrisko } 1248233711Sambrisko if (sc->request_desc_pool != NULL) { 1249233711Sambrisko free(sc->request_desc_pool, M_MFIBUF); 1250233711Sambrisko sc->request_desc_pool = NULL; 1251233711Sambrisko } 1252233711Sambrisko } 1253157114Sscottl if (sc->mfi_buffer_dmat != NULL) 1254157114Sscottl bus_dma_tag_destroy(sc->mfi_buffer_dmat); 1255157114Sscottl if (sc->mfi_parent_dmat != NULL) 1256157114Sscottl bus_dma_tag_destroy(sc->mfi_parent_dmat); 1257157114Sscottl 1258171821Sjhb if (mtx_initialized(&sc->mfi_io_lock)) { 1259157114Sscottl mtx_destroy(&sc->mfi_io_lock); 1260171821Sjhb sx_destroy(&sc->mfi_config_lock); 1261171821Sjhb } 1262157114Sscottl 1263157114Sscottl return; 1264157114Sscottl} 1265157114Sscottl 1266157114Sscottlstatic void 1267157114Sscottlmfi_startup(void *arg) 1268157114Sscottl{ 1269157114Sscottl struct mfi_softc *sc; 1270157114Sscottl 1271157114Sscottl sc = (struct mfi_softc *)arg; 1272157114Sscottl 1273157114Sscottl config_intrhook_disestablish(&sc->mfi_ich); 1274157114Sscottl 1275171980Sscottl sc->mfi_enable_intr(sc); 1276171821Sjhb sx_xlock(&sc->mfi_config_lock); 1277163398Sscottl mtx_lock(&sc->mfi_io_lock); 1278159811Sps mfi_ldprobe(sc); 1279233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) 1280233711Sambrisko mfi_syspdprobe(sc); 1281163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1282171821Sjhb sx_xunlock(&sc->mfi_config_lock); 1283157114Sscottl} 1284157114Sscottl 1285157114Sscottlstatic void 1286157114Sscottlmfi_intr(void *arg) 1287157114Sscottl{ 1288157114Sscottl struct mfi_softc *sc; 1289157114Sscottl struct mfi_command *cm; 1290171980Sscottl uint32_t pi, ci, context; 1291157114Sscottl 1292157114Sscottl sc = (struct mfi_softc *)arg; 1293157114Sscottl 1294171980Sscottl if (sc->mfi_check_clear_intr(sc)) 1295157114Sscottl return; 1296163398Sscottl 1297233711Sambriskorestart: 1298157114Sscottl pi = sc->mfi_comms->hw_pi; 1299157114Sscottl ci = sc->mfi_comms->hw_ci; 1300157114Sscottl mtx_lock(&sc->mfi_io_lock); 1301157114Sscottl while (ci != pi) { 1302157114Sscottl context = sc->mfi_comms->hw_reply_q[ci]; 1303170284Sambrisko if (context < sc->mfi_max_fw_cmds) { 1304170284Sambrisko cm = &sc->mfi_commands[context]; 1305170284Sambrisko mfi_remove_busy(cm); 1306170284Sambrisko cm->cm_error = 0; 1307170284Sambrisko mfi_complete(sc, cm); 1308170284Sambrisko } 1309247369Ssmh if (++ci == (sc->mfi_max_fw_cmds + 1)) 1310157114Sscottl ci = 0; 1311157114Sscottl } 1312157114Sscottl 1313157114Sscottl sc->mfi_comms->hw_ci = ci; 1314157114Sscottl 1315163398Sscottl /* Give defered I/O a chance to run */ 1316247369Ssmh sc->mfi_flags &= ~MFI_FLAGS_QFRZN; 1317163398Sscottl mfi_startio(sc); 1318163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1319163398Sscottl 1320233711Sambrisko /* 1321233711Sambrisko * Dummy read to flush the bus; this ensures that the indexes are up 1322233711Sambrisko * to date. Restart processing if more commands have come it. 1323233711Sambrisko */ 1324233711Sambrisko (void)sc->mfi_read_fw_status(sc); 1325233711Sambrisko if (pi != sc->mfi_comms->hw_pi) 1326233711Sambrisko goto restart; 1327233711Sambrisko 1328157114Sscottl return; 1329157114Sscottl} 1330157114Sscottl 1331157114Sscottlint 1332157114Sscottlmfi_shutdown(struct mfi_softc *sc) 1333157114Sscottl{ 1334157114Sscottl struct mfi_dcmd_frame *dcmd; 1335157114Sscottl struct mfi_command *cm; 1336157114Sscottl int error; 1337157114Sscottl 1338242681Sambrisko 1339247369Ssmh if (sc->mfi_aen_cm != NULL) { 1340242681Sambrisko sc->cm_aen_abort = 1; 1341242681Sambrisko mfi_abort(sc, &sc->mfi_aen_cm); 1342247369Ssmh } 1343242681Sambrisko 1344247369Ssmh if (sc->mfi_map_sync_cm != NULL) { 1345242681Sambrisko sc->cm_map_abort = 1; 1346242681Sambrisko mfi_abort(sc, &sc->mfi_map_sync_cm); 1347247369Ssmh } 1348242681Sambrisko 1349159806Sps mtx_lock(&sc->mfi_io_lock); 1350159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0); 1351163398Sscottl if (error) { 1352163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1353159806Sps return (error); 1354163398Sscottl } 1355157114Sscottl 1356157114Sscottl dcmd = &cm->cm_frame->dcmd; 1357157114Sscottl dcmd->header.flags = MFI_FRAME_DIR_NONE; 1358164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 1359164375Sscottl cm->cm_data = NULL; 1360157114Sscottl 1361247369Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) 1362157114Sscottl device_printf(sc->mfi_dev, "Failed to shutdown controller\n"); 1363157114Sscottl 1364159812Sps mfi_release_command(cm); 1365163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1366157114Sscottl return (error); 1367157114Sscottl} 1368157114Sscottl 1369157114Sscottlstatic void 1370233711Sambriskomfi_syspdprobe(struct mfi_softc *sc) 1371233711Sambrisko{ 1372233711Sambrisko struct mfi_frame_header *hdr; 1373233711Sambrisko struct mfi_command *cm = NULL; 1374233711Sambrisko struct mfi_pd_list *pdlist = NULL; 1375233711Sambrisko struct mfi_system_pd *syspd, *tmp; 1376242681Sambrisko struct mfi_system_pending *syspd_pend; 1377233711Sambrisko int error, i, found; 1378233711Sambrisko 1379233711Sambrisko sx_assert(&sc->mfi_config_lock, SA_XLOCKED); 1380233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1381233711Sambrisko /* Add SYSTEM PD's */ 1382233711Sambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY, 1383233711Sambrisko (void **)&pdlist, sizeof(*pdlist)); 1384235016Sambrisko if (error) { 1385233711Sambrisko device_printf(sc->mfi_dev, 1386233711Sambrisko "Error while forming SYSTEM PD list\n"); 1387233711Sambrisko goto out; 1388233711Sambrisko } 1389233711Sambrisko 1390233711Sambrisko cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1391233711Sambrisko cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST; 1392233711Sambrisko cm->cm_frame->dcmd.mbox[1] = 0; 1393233711Sambrisko if (mfi_mapcmd(sc, cm) != 0) { 1394233711Sambrisko device_printf(sc->mfi_dev, 1395233711Sambrisko "Failed to get syspd device listing\n"); 1396233711Sambrisko goto out; 1397233711Sambrisko } 1398233711Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap, 1399233711Sambrisko BUS_DMASYNC_POSTREAD); 1400233711Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1401233711Sambrisko hdr = &cm->cm_frame->header; 1402233711Sambrisko if (hdr->cmd_status != MFI_STAT_OK) { 1403233711Sambrisko device_printf(sc->mfi_dev, 1404233711Sambrisko "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status); 1405233711Sambrisko goto out; 1406233711Sambrisko } 1407233711Sambrisko /* Get each PD and add it to the system */ 1408233711Sambrisko for (i = 0; i < pdlist->count; i++) { 1409233711Sambrisko if (pdlist->addr[i].device_id == 1410233711Sambrisko pdlist->addr[i].encl_device_id) 1411233711Sambrisko continue; 1412233711Sambrisko found = 0; 1413233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { 1414233711Sambrisko if (syspd->pd_id == pdlist->addr[i].device_id) 1415233711Sambrisko found = 1; 1416233711Sambrisko } 1417242681Sambrisko TAILQ_FOREACH(syspd_pend, &sc->mfi_syspd_pend_tqh, pd_link) { 1418242681Sambrisko if (syspd_pend->pd_id == pdlist->addr[i].device_id) 1419242681Sambrisko found = 1; 1420242681Sambrisko } 1421233711Sambrisko if (found == 0) 1422233711Sambrisko mfi_add_sys_pd(sc, pdlist->addr[i].device_id); 1423233711Sambrisko } 1424233711Sambrisko /* Delete SYSPD's whose state has been changed */ 1425233711Sambrisko TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) { 1426233711Sambrisko found = 0; 1427233711Sambrisko for (i = 0; i < pdlist->count; i++) { 1428247369Ssmh if (syspd->pd_id == pdlist->addr[i].device_id) { 1429233711Sambrisko found = 1; 1430247369Ssmh break; 1431247369Ssmh } 1432233711Sambrisko } 1433233711Sambrisko if (found == 0) { 1434233711Sambrisko printf("DELETE\n"); 1435233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1436233711Sambrisko mtx_lock(&Giant); 1437233711Sambrisko device_delete_child(sc->mfi_dev, syspd->pd_dev); 1438233711Sambrisko mtx_unlock(&Giant); 1439233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1440233711Sambrisko } 1441233711Sambrisko } 1442233711Sambriskoout: 1443233711Sambrisko if (pdlist) 1444233711Sambrisko free(pdlist, M_MFIBUF); 1445233711Sambrisko if (cm) 1446233711Sambrisko mfi_release_command(cm); 1447233711Sambrisko 1448233711Sambrisko return; 1449233711Sambrisko} 1450233711Sambrisko 1451233711Sambriskostatic void 1452159811Spsmfi_ldprobe(struct mfi_softc *sc) 1453157114Sscottl{ 1454159811Sps struct mfi_frame_header *hdr; 1455159811Sps struct mfi_command *cm = NULL; 1456159811Sps struct mfi_ld_list *list = NULL; 1457171821Sjhb struct mfi_disk *ld; 1458242681Sambrisko struct mfi_disk_pending *ld_pend; 1459159811Sps int error, i; 1460157114Sscottl 1461171821Sjhb sx_assert(&sc->mfi_config_lock, SA_XLOCKED); 1462163398Sscottl mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1463163398Sscottl 1464159811Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST, 1465159811Sps (void **)&list, sizeof(*list)); 1466159811Sps if (error) 1467159811Sps goto out; 1468159811Sps 1469159811Sps cm->cm_flags = MFI_CMD_DATAIN; 1470159811Sps if (mfi_wait_command(sc, cm) != 0) { 1471159811Sps device_printf(sc->mfi_dev, "Failed to get device listing\n"); 1472159811Sps goto out; 1473157114Sscottl } 1474157114Sscottl 1475157114Sscottl hdr = &cm->cm_frame->header; 1476159811Sps if (hdr->cmd_status != MFI_STAT_OK) { 1477159811Sps device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n", 1478159811Sps hdr->cmd_status); 1479159811Sps goto out; 1480157114Sscottl } 1481157114Sscottl 1482171821Sjhb for (i = 0; i < list->ld_count; i++) { 1483171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 1484171821Sjhb if (ld->ld_id == list->ld_list[i].ld.v.target_id) 1485171821Sjhb goto skip_add; 1486171821Sjhb } 1487242681Sambrisko TAILQ_FOREACH(ld_pend, &sc->mfi_ld_pend_tqh, ld_link) { 1488242681Sambrisko if (ld_pend->ld_id == list->ld_list[i].ld.v.target_id) 1489242681Sambrisko goto skip_add; 1490242681Sambrisko } 1491163398Sscottl mfi_add_ld(sc, list->ld_list[i].ld.v.target_id); 1492171821Sjhb skip_add:; 1493171821Sjhb } 1494159811Spsout: 1495159811Sps if (list) 1496159811Sps free(list, M_MFIBUF); 1497159811Sps if (cm) 1498157114Sscottl mfi_release_command(cm); 1499163398Sscottl 1500159811Sps return; 1501157114Sscottl} 1502157114Sscottl 1503180038Sjhb/* 1504180038Sjhb * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If 1505180038Sjhb * the bits in 24-31 are all set, then it is the number of seconds since 1506180038Sjhb * boot. 1507180038Sjhb */ 1508180038Sjhbstatic const char * 1509180038Sjhbformat_timestamp(uint32_t timestamp) 1510158737Sambrisko{ 1511180038Sjhb static char buffer[32]; 1512180038Sjhb 1513180038Sjhb if ((timestamp & 0xff000000) == 0xff000000) 1514180038Sjhb snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & 1515180038Sjhb 0x00ffffff); 1516180038Sjhb else 1517180038Sjhb snprintf(buffer, sizeof(buffer), "%us", timestamp); 1518180038Sjhb return (buffer); 1519180038Sjhb} 1520180038Sjhb 1521180038Sjhbstatic const char * 1522180038Sjhbformat_class(int8_t class) 1523180038Sjhb{ 1524180038Sjhb static char buffer[6]; 1525180038Sjhb 1526180038Sjhb switch (class) { 1527180038Sjhb case MFI_EVT_CLASS_DEBUG: 1528180038Sjhb return ("debug"); 1529180038Sjhb case MFI_EVT_CLASS_PROGRESS: 1530180038Sjhb return ("progress"); 1531180038Sjhb case MFI_EVT_CLASS_INFO: 1532180038Sjhb return ("info"); 1533180038Sjhb case MFI_EVT_CLASS_WARNING: 1534180038Sjhb return ("WARN"); 1535180038Sjhb case MFI_EVT_CLASS_CRITICAL: 1536180038Sjhb return ("CRIT"); 1537180038Sjhb case MFI_EVT_CLASS_FATAL: 1538180038Sjhb return ("FATAL"); 1539180038Sjhb case MFI_EVT_CLASS_DEAD: 1540180038Sjhb return ("DEAD"); 1541158737Sambrisko default: 1542180038Sjhb snprintf(buffer, sizeof(buffer), "%d", class); 1543180038Sjhb return (buffer); 1544158737Sambrisko } 1545158737Sambrisko} 1546158737Sambrisko 1547180038Sjhbstatic void 1548180038Sjhbmfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) 1549180038Sjhb{ 1550233711Sambrisko struct mfi_system_pd *syspd = NULL; 1551180038Sjhb 1552200238Sjkim device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq, 1553222589Semaste format_timestamp(detail->time), detail->evt_class.members.locale, 1554233711Sambrisko format_class(detail->evt_class.members.evt_class), 1555233711Sambrisko detail->description); 1556233711Sambrisko 1557233711Sambrisko /* Don't act on old AEN's or while shutting down */ 1558233711Sambrisko if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching) 1559233711Sambrisko return; 1560233711Sambrisko 1561233711Sambrisko switch (detail->arg_type) { 1562233711Sambrisko case MR_EVT_ARGS_NONE: 1563233711Sambrisko if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) { 1564233711Sambrisko device_printf(sc->mfi_dev, "HostBus scan raised\n"); 1565233711Sambrisko if (mfi_detect_jbod_change) { 1566233711Sambrisko /* 1567233711Sambrisko * Probe for new SYSPD's and Delete 1568233711Sambrisko * invalid SYSPD's 1569233711Sambrisko */ 1570233711Sambrisko sx_xlock(&sc->mfi_config_lock); 1571233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1572233711Sambrisko mfi_syspdprobe(sc); 1573233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1574233711Sambrisko sx_xunlock(&sc->mfi_config_lock); 1575233711Sambrisko } 1576233711Sambrisko } 1577233711Sambrisko break; 1578233711Sambrisko case MR_EVT_ARGS_LD_STATE: 1579233711Sambrisko /* During load time driver reads all the events starting 1580233711Sambrisko * from the one that has been logged after shutdown. Avoid 1581233711Sambrisko * these old events. 1582233711Sambrisko */ 1583233711Sambrisko if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) { 1584233711Sambrisko /* Remove the LD */ 1585233711Sambrisko struct mfi_disk *ld; 1586233711Sambrisko TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 1587233711Sambrisko if (ld->ld_id == 1588233711Sambrisko detail->args.ld_state.ld.target_id) 1589233711Sambrisko break; 1590233711Sambrisko } 1591233711Sambrisko /* 1592233711Sambrisko Fix: for kernel panics when SSCD is removed 1593233711Sambrisko KASSERT(ld != NULL, ("volume dissappeared")); 1594233711Sambrisko */ 1595233711Sambrisko if (ld != NULL) { 1596233711Sambrisko mtx_lock(&Giant); 1597233711Sambrisko device_delete_child(sc->mfi_dev, ld->ld_dev); 1598233711Sambrisko mtx_unlock(&Giant); 1599233711Sambrisko } 1600233711Sambrisko } 1601233711Sambrisko break; 1602233711Sambrisko case MR_EVT_ARGS_PD: 1603233711Sambrisko if (detail->code == MR_EVT_PD_REMOVED) { 1604233711Sambrisko if (mfi_detect_jbod_change) { 1605233711Sambrisko /* 1606233711Sambrisko * If the removed device is a SYSPD then 1607233711Sambrisko * delete it 1608233711Sambrisko */ 1609233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, 1610233711Sambrisko pd_link) { 1611233711Sambrisko if (syspd->pd_id == 1612233711Sambrisko detail->args.pd.device_id) { 1613233711Sambrisko mtx_lock(&Giant); 1614233711Sambrisko device_delete_child( 1615233711Sambrisko sc->mfi_dev, 1616233711Sambrisko syspd->pd_dev); 1617233711Sambrisko mtx_unlock(&Giant); 1618233711Sambrisko break; 1619233711Sambrisko } 1620233711Sambrisko } 1621233711Sambrisko } 1622233711Sambrisko } 1623233711Sambrisko if (detail->code == MR_EVT_PD_INSERTED) { 1624233711Sambrisko if (mfi_detect_jbod_change) { 1625233711Sambrisko /* Probe for new SYSPD's */ 1626233711Sambrisko sx_xlock(&sc->mfi_config_lock); 1627233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1628233711Sambrisko mfi_syspdprobe(sc); 1629233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1630233711Sambrisko sx_xunlock(&sc->mfi_config_lock); 1631233711Sambrisko } 1632233711Sambrisko } 1633242726Sambrisko if (sc->mfi_cam_rescan_cb != NULL && 1634242726Sambrisko (detail->code == MR_EVT_PD_INSERTED || 1635242726Sambrisko detail->code == MR_EVT_PD_REMOVED)) { 1636242726Sambrisko sc->mfi_cam_rescan_cb(sc, detail->args.pd.device_id); 1637242726Sambrisko } 1638233711Sambrisko break; 1639233711Sambrisko } 1640180038Sjhb} 1641180038Sjhb 1642233711Sambriskostatic void 1643233711Sambriskomfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) 1644233711Sambrisko{ 1645233711Sambrisko struct mfi_evt_queue_elm *elm; 1646233711Sambrisko 1647233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1648233711Sambrisko elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO); 1649233711Sambrisko if (elm == NULL) 1650233711Sambrisko return; 1651233711Sambrisko memcpy(&elm->detail, detail, sizeof(*detail)); 1652233711Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link); 1653233711Sambrisko taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task); 1654233711Sambrisko} 1655233711Sambrisko 1656233711Sambriskostatic void 1657233711Sambriskomfi_handle_evt(void *context, int pending) 1658233711Sambrisko{ 1659233711Sambrisko TAILQ_HEAD(,mfi_evt_queue_elm) queue; 1660233711Sambrisko struct mfi_softc *sc; 1661233711Sambrisko struct mfi_evt_queue_elm *elm; 1662233711Sambrisko 1663233711Sambrisko sc = context; 1664233711Sambrisko TAILQ_INIT(&queue); 1665233711Sambrisko mtx_lock(&sc->mfi_io_lock); 1666233711Sambrisko TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link); 1667233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 1668233711Sambrisko while ((elm = TAILQ_FIRST(&queue)) != NULL) { 1669233711Sambrisko TAILQ_REMOVE(&queue, elm, link); 1670233711Sambrisko mfi_decode_evt(sc, &elm->detail); 1671233711Sambrisko free(elm, M_MFIBUF); 1672233711Sambrisko } 1673233711Sambrisko} 1674233711Sambrisko 1675157114Sscottlstatic int 1676158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale) 1677158737Sambrisko{ 1678158737Sambrisko struct mfi_command *cm; 1679158737Sambrisko struct mfi_dcmd_frame *dcmd; 1680158737Sambrisko union mfi_evt current_aen, prior_aen; 1681159806Sps struct mfi_evt_detail *ed = NULL; 1682163398Sscottl int error = 0; 1683158737Sambrisko 1684247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1685247369Ssmh 1686158737Sambrisko current_aen.word = locale; 1687158737Sambrisko if (sc->mfi_aen_cm != NULL) { 1688158737Sambrisko prior_aen.word = 1689158737Sambrisko ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1]; 1690222589Semaste if (prior_aen.members.evt_class <= current_aen.members.evt_class && 1691158737Sambrisko !((prior_aen.members.locale & current_aen.members.locale) 1692158737Sambrisko ^current_aen.members.locale)) { 1693158737Sambrisko return (0); 1694158737Sambrisko } else { 1695158737Sambrisko prior_aen.members.locale |= current_aen.members.locale; 1696222589Semaste if (prior_aen.members.evt_class 1697222589Semaste < current_aen.members.evt_class) 1698222589Semaste current_aen.members.evt_class = 1699222589Semaste prior_aen.members.evt_class; 1700242681Sambrisko mfi_abort(sc, &sc->mfi_aen_cm); 1701158737Sambrisko } 1702158737Sambrisko } 1703158737Sambrisko 1704159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT, 1705159806Sps (void **)&ed, sizeof(*ed)); 1706247369Ssmh if (error) 1707163398Sscottl goto out; 1708158737Sambrisko 1709158737Sambrisko dcmd = &cm->cm_frame->dcmd; 1710158737Sambrisko ((uint32_t *)&dcmd->mbox)[0] = seq; 1711158737Sambrisko ((uint32_t *)&dcmd->mbox)[1] = locale; 1712158737Sambrisko cm->cm_flags = MFI_CMD_DATAIN; 1713158737Sambrisko cm->cm_complete = mfi_aen_complete; 1714158737Sambrisko 1715233711Sambrisko sc->last_seq_num = seq; 1716158737Sambrisko sc->mfi_aen_cm = cm; 1717158737Sambrisko 1718158737Sambrisko mfi_enqueue_ready(cm); 1719158737Sambrisko mfi_startio(sc); 1720158737Sambrisko 1721163398Sscottlout: 1722163398Sscottl return (error); 1723158737Sambrisko} 1724158737Sambrisko 1725158737Sambriskostatic void 1726158737Sambriskomfi_aen_complete(struct mfi_command *cm) 1727158737Sambrisko{ 1728158737Sambrisko struct mfi_frame_header *hdr; 1729158737Sambrisko struct mfi_softc *sc; 1730158737Sambrisko struct mfi_evt_detail *detail; 1731163398Sscottl struct mfi_aen *mfi_aen_entry, *tmp; 1732158737Sambrisko int seq = 0, aborted = 0; 1733158737Sambrisko 1734158737Sambrisko sc = cm->cm_sc; 1735233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1736233711Sambrisko 1737158737Sambrisko if (sc->mfi_aen_cm == NULL) 1738158737Sambrisko return; 1739158737Sambrisko 1740247369Ssmh hdr = &cm->cm_frame->header; 1741247369Ssmh 1742235014Sambrisko if (sc->cm_aen_abort || 1743224039Sjhb hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 1744235014Sambrisko sc->cm_aen_abort = 0; 1745158737Sambrisko aborted = 1; 1746158737Sambrisko } else { 1747158737Sambrisko sc->mfi_aen_triggered = 1; 1748163398Sscottl if (sc->mfi_poll_waiting) { 1749163398Sscottl sc->mfi_poll_waiting = 0; 1750158737Sambrisko selwakeup(&sc->mfi_select); 1751163398Sscottl } 1752158737Sambrisko detail = cm->cm_data; 1753233711Sambrisko mfi_queue_evt(sc, detail); 1754158737Sambrisko seq = detail->seq + 1; 1755233711Sambrisko TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, 1756233711Sambrisko tmp) { 1757158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 1758158737Sambrisko aen_link); 1759163398Sscottl PROC_LOCK(mfi_aen_entry->p); 1760225617Skmacy kern_psignal(mfi_aen_entry->p, SIGIO); 1761163398Sscottl PROC_UNLOCK(mfi_aen_entry->p); 1762158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 1763158737Sambrisko } 1764158737Sambrisko } 1765158737Sambrisko 1766158737Sambrisko free(cm->cm_data, M_MFIBUF); 1767247369Ssmh wakeup(&sc->mfi_aen_cm); 1768158737Sambrisko sc->mfi_aen_cm = NULL; 1769158737Sambrisko mfi_release_command(cm); 1770158737Sambrisko 1771158737Sambrisko /* set it up again so the driver can catch more events */ 1772247369Ssmh if (!aborted) 1773158737Sambrisko mfi_aen_setup(sc, seq); 1774158737Sambrisko} 1775158737Sambrisko 1776180037Sjhb#define MAX_EVENTS 15 1777180037Sjhb 1778158737Sambriskostatic int 1779180037Sjhbmfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) 1780158737Sambrisko{ 1781158737Sambrisko struct mfi_command *cm; 1782158737Sambrisko struct mfi_dcmd_frame *dcmd; 1783162118Sambrisko struct mfi_evt_list *el; 1784180037Sjhb union mfi_evt class_locale; 1785180037Sjhb int error, i, seq, size; 1786158737Sambrisko 1787247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1788247369Ssmh 1789180037Sjhb class_locale.members.reserved = 0; 1790180037Sjhb class_locale.members.locale = mfi_event_locale; 1791222589Semaste class_locale.members.evt_class = mfi_event_class; 1792158737Sambrisko 1793162118Sambrisko size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) 1794162118Sambrisko * (MAX_EVENTS - 1); 1795162118Sambrisko el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO); 1796180037Sjhb if (el == NULL) 1797158737Sambrisko return (ENOMEM); 1798158737Sambrisko 1799180037Sjhb for (seq = start_seq;;) { 1800180037Sjhb if ((cm = mfi_dequeue_free(sc)) == NULL) { 1801180037Sjhb free(el, M_MFIBUF); 1802180037Sjhb return (EBUSY); 1803180037Sjhb } 1804158737Sambrisko 1805180037Sjhb dcmd = &cm->cm_frame->dcmd; 1806180037Sjhb bzero(dcmd->mbox, MFI_MBOX_SIZE); 1807180037Sjhb dcmd->header.cmd = MFI_CMD_DCMD; 1808180037Sjhb dcmd->header.timeout = 0; 1809180037Sjhb dcmd->header.data_len = size; 1810180037Sjhb dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET; 1811180037Sjhb ((uint32_t *)&dcmd->mbox)[0] = seq; 1812180037Sjhb ((uint32_t *)&dcmd->mbox)[1] = class_locale.word; 1813180037Sjhb cm->cm_sg = &dcmd->sgl; 1814180037Sjhb cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 1815180037Sjhb cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1816180037Sjhb cm->cm_data = el; 1817180037Sjhb cm->cm_len = size; 1818180037Sjhb 1819180037Sjhb if ((error = mfi_mapcmd(sc, cm)) != 0) { 1820180037Sjhb device_printf(sc->mfi_dev, 1821180037Sjhb "Failed to get controller entries\n"); 1822180037Sjhb mfi_release_command(cm); 1823180037Sjhb break; 1824180037Sjhb } 1825180037Sjhb 1826180037Sjhb bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1827180037Sjhb BUS_DMASYNC_POSTREAD); 1828180037Sjhb bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1829180037Sjhb 1830180037Sjhb if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) { 1831180037Sjhb mfi_release_command(cm); 1832180037Sjhb break; 1833180037Sjhb } 1834180037Sjhb if (dcmd->header.cmd_status != MFI_STAT_OK) { 1835180037Sjhb device_printf(sc->mfi_dev, 1836180037Sjhb "Error %d fetching controller entries\n", 1837180037Sjhb dcmd->header.cmd_status); 1838180037Sjhb mfi_release_command(cm); 1839247369Ssmh error = EIO; 1840180037Sjhb break; 1841180037Sjhb } 1842158737Sambrisko mfi_release_command(cm); 1843158737Sambrisko 1844162473Sambrisko for (i = 0; i < el->count; i++) { 1845180037Sjhb /* 1846180037Sjhb * If this event is newer than 'stop_seq' then 1847180037Sjhb * break out of the loop. Note that the log 1848180037Sjhb * is a circular buffer so we have to handle 1849180037Sjhb * the case that our stop point is earlier in 1850180037Sjhb * the buffer than our start point. 1851180037Sjhb */ 1852180037Sjhb if (el->event[i].seq >= stop_seq) { 1853180037Sjhb if (start_seq <= stop_seq) 1854180037Sjhb break; 1855180037Sjhb else if (el->event[i].seq < start_seq) 1856180037Sjhb break; 1857180037Sjhb } 1858233711Sambrisko mfi_queue_evt(sc, &el->event[i]); 1859162473Sambrisko } 1860180037Sjhb seq = el->event[el->count - 1].seq + 1; 1861162118Sambrisko } 1862158737Sambrisko 1863180037Sjhb free(el, M_MFIBUF); 1864247369Ssmh return (error); 1865158737Sambrisko} 1866158737Sambrisko 1867158737Sambriskostatic int 1868159811Spsmfi_add_ld(struct mfi_softc *sc, int id) 1869157114Sscottl{ 1870157114Sscottl struct mfi_command *cm; 1871159811Sps struct mfi_dcmd_frame *dcmd = NULL; 1872159811Sps struct mfi_ld_info *ld_info = NULL; 1873242681Sambrisko struct mfi_disk_pending *ld_pend; 1874159811Sps int error; 1875157114Sscottl 1876159811Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1877159811Sps 1878242681Sambrisko ld_pend = malloc(sizeof(*ld_pend), M_MFIBUF, M_NOWAIT | M_ZERO); 1879242681Sambrisko if (ld_pend != NULL) { 1880242681Sambrisko ld_pend->ld_id = id; 1881242681Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_ld_pend_tqh, ld_pend, ld_link); 1882242681Sambrisko } 1883242681Sambrisko 1884159811Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO, 1885159811Sps (void **)&ld_info, sizeof(*ld_info)); 1886159811Sps if (error) { 1887159811Sps device_printf(sc->mfi_dev, 1888159811Sps "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error); 1889159811Sps if (ld_info) 1890159811Sps free(ld_info, M_MFIBUF); 1891159811Sps return (error); 1892157624Sscottl } 1893159811Sps cm->cm_flags = MFI_CMD_DATAIN; 1894159811Sps dcmd = &cm->cm_frame->dcmd; 1895159811Sps dcmd->mbox[0] = id; 1896160052Sambrisko if (mfi_wait_command(sc, cm) != 0) { 1897160052Sambrisko device_printf(sc->mfi_dev, 1898160052Sambrisko "Failed to get logical drive: %d\n", id); 1899160052Sambrisko free(ld_info, M_MFIBUF); 1900160052Sambrisko return (0); 1901160052Sambrisko } 1902233711Sambrisko if (ld_info->ld_config.params.isSSCD != 1) 1903233711Sambrisko mfi_add_ld_complete(cm); 1904233711Sambrisko else { 1905233711Sambrisko mfi_release_command(cm); 1906233711Sambrisko if (ld_info) /* SSCD drives ld_info free here */ 1907233711Sambrisko free(ld_info, M_MFIBUF); 1908233711Sambrisko } 1909157114Sscottl return (0); 1910157114Sscottl} 1911157114Sscottl 1912157114Sscottlstatic void 1913159811Spsmfi_add_ld_complete(struct mfi_command *cm) 1914157114Sscottl{ 1915157114Sscottl struct mfi_frame_header *hdr; 1916159811Sps struct mfi_ld_info *ld_info; 1917157114Sscottl struct mfi_softc *sc; 1918159811Sps device_t child; 1919157114Sscottl 1920157114Sscottl sc = cm->cm_sc; 1921157114Sscottl hdr = &cm->cm_frame->header; 1922159811Sps ld_info = cm->cm_private; 1923157114Sscottl 1924242681Sambrisko if (sc->cm_map_abort || hdr->cmd_status != MFI_STAT_OK) { 1925159811Sps free(ld_info, M_MFIBUF); 1926242681Sambrisko wakeup(&sc->mfi_map_sync_cm); 1927157114Sscottl mfi_release_command(cm); 1928157114Sscottl return; 1929157114Sscottl } 1930242681Sambrisko wakeup(&sc->mfi_map_sync_cm); 1931157114Sscottl mfi_release_command(cm); 1932157114Sscottl 1933169611Sscottl mtx_unlock(&sc->mfi_io_lock); 1934196403Sjhb mtx_lock(&Giant); 1935157114Sscottl if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) { 1936157114Sscottl device_printf(sc->mfi_dev, "Failed to add logical disk\n"); 1937159811Sps free(ld_info, M_MFIBUF); 1938196403Sjhb mtx_unlock(&Giant); 1939169611Sscottl mtx_lock(&sc->mfi_io_lock); 1940159811Sps return; 1941157114Sscottl } 1942157114Sscottl 1943169451Sscottl device_set_ivars(child, ld_info); 1944157114Sscottl device_set_desc(child, "MFI Logical Disk"); 1945157114Sscottl bus_generic_attach(sc->mfi_dev); 1946196403Sjhb mtx_unlock(&Giant); 1947157114Sscottl mtx_lock(&sc->mfi_io_lock); 1948157114Sscottl} 1949163399Sscottl 1950233711Sambriskostatic int mfi_add_sys_pd(struct mfi_softc *sc, int id) 1951233711Sambrisko{ 1952233711Sambrisko struct mfi_command *cm; 1953233711Sambrisko struct mfi_dcmd_frame *dcmd = NULL; 1954233711Sambrisko struct mfi_pd_info *pd_info = NULL; 1955242681Sambrisko struct mfi_system_pending *syspd_pend; 1956233711Sambrisko int error; 1957233711Sambrisko 1958233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1959233711Sambrisko 1960242681Sambrisko syspd_pend = malloc(sizeof(*syspd_pend), M_MFIBUF, M_NOWAIT | M_ZERO); 1961242681Sambrisko if (syspd_pend != NULL) { 1962242681Sambrisko syspd_pend->pd_id = id; 1963242681Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_syspd_pend_tqh, syspd_pend, pd_link); 1964242681Sambrisko } 1965242681Sambrisko 1966233711Sambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO, 1967233711Sambrisko (void **)&pd_info, sizeof(*pd_info)); 1968233711Sambrisko if (error) { 1969233711Sambrisko device_printf(sc->mfi_dev, 1970233711Sambrisko "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n", 1971233711Sambrisko error); 1972233711Sambrisko if (pd_info) 1973233711Sambrisko free(pd_info, M_MFIBUF); 1974233711Sambrisko return (error); 1975233711Sambrisko } 1976233711Sambrisko cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1977233711Sambrisko dcmd = &cm->cm_frame->dcmd; 1978233711Sambrisko dcmd->mbox[0]=id; 1979233711Sambrisko dcmd->header.scsi_status = 0; 1980233711Sambrisko dcmd->header.pad0 = 0; 1981247369Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) { 1982233711Sambrisko device_printf(sc->mfi_dev, 1983233711Sambrisko "Failed to get physical drive info %d\n", id); 1984233711Sambrisko free(pd_info, M_MFIBUF); 1985247369Ssmh mfi_release_command(cm); 1986247369Ssmh return (error); 1987233711Sambrisko } 1988233711Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1989233711Sambrisko BUS_DMASYNC_POSTREAD); 1990233711Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1991233711Sambrisko mfi_add_sys_pd_complete(cm); 1992233711Sambrisko return (0); 1993233711Sambrisko} 1994233711Sambrisko 1995233711Sambriskostatic void 1996233711Sambriskomfi_add_sys_pd_complete(struct mfi_command *cm) 1997233711Sambrisko{ 1998233711Sambrisko struct mfi_frame_header *hdr; 1999233711Sambrisko struct mfi_pd_info *pd_info; 2000233711Sambrisko struct mfi_softc *sc; 2001233711Sambrisko device_t child; 2002233711Sambrisko 2003233711Sambrisko sc = cm->cm_sc; 2004233711Sambrisko hdr = &cm->cm_frame->header; 2005233711Sambrisko pd_info = cm->cm_private; 2006233711Sambrisko 2007233711Sambrisko if (hdr->cmd_status != MFI_STAT_OK) { 2008233711Sambrisko free(pd_info, M_MFIBUF); 2009233711Sambrisko mfi_release_command(cm); 2010233711Sambrisko return; 2011233711Sambrisko } 2012233711Sambrisko if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) { 2013233711Sambrisko device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n", 2014233711Sambrisko pd_info->ref.v.device_id); 2015233711Sambrisko free(pd_info, M_MFIBUF); 2016233711Sambrisko mfi_release_command(cm); 2017233711Sambrisko return; 2018233711Sambrisko } 2019233711Sambrisko mfi_release_command(cm); 2020233711Sambrisko 2021233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 2022233711Sambrisko mtx_lock(&Giant); 2023233711Sambrisko if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) { 2024233711Sambrisko device_printf(sc->mfi_dev, "Failed to add system pd\n"); 2025233711Sambrisko free(pd_info, M_MFIBUF); 2026233711Sambrisko mtx_unlock(&Giant); 2027233711Sambrisko mtx_lock(&sc->mfi_io_lock); 2028233711Sambrisko return; 2029233711Sambrisko } 2030233711Sambrisko 2031233711Sambrisko device_set_ivars(child, pd_info); 2032233711Sambrisko device_set_desc(child, "MFI System PD"); 2033233711Sambrisko bus_generic_attach(sc->mfi_dev); 2034233711Sambrisko mtx_unlock(&Giant); 2035233711Sambrisko mtx_lock(&sc->mfi_io_lock); 2036233711Sambrisko} 2037235016Sambrisko 2038157114Sscottlstatic struct mfi_command * 2039157114Sscottlmfi_bio_command(struct mfi_softc *sc) 2040157114Sscottl{ 2041157114Sscottl struct bio *bio; 2042233711Sambrisko struct mfi_command *cm = NULL; 2043157114Sscottl 2044233711Sambrisko /*reserving two commands to avoid starvation for IOCTL*/ 2045235016Sambrisko if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) { 2046157114Sscottl return (NULL); 2047233711Sambrisko } 2048157114Sscottl if ((bio = mfi_dequeue_bio(sc)) == NULL) { 2049157114Sscottl return (NULL); 2050157114Sscottl } 2051233711Sambrisko if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) { 2052233711Sambrisko cm = mfi_build_ldio(sc, bio); 2053233711Sambrisko } else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) { 2054233711Sambrisko cm = mfi_build_syspdio(sc, bio); 2055233711Sambrisko } 2056233711Sambrisko if (!cm) 2057233711Sambrisko mfi_enqueue_bio(sc, bio); 2058233711Sambrisko return cm; 2059233711Sambrisko} 2060242497Sdelphij 2061242681Sambrisko/* 2062242681Sambrisko * mostly copied from cam/scsi/scsi_all.c:scsi_read_write 2063242681Sambrisko */ 2064242681Sambrisko 2065242681Sambriskoint 2066242681Sambriskomfi_build_cdb(int readop, uint8_t byte2, u_int64_t lba, u_int32_t block_count, uint8_t *cdb) 2067242497Sdelphij{ 2068242497Sdelphij int cdb_len; 2069242497Sdelphij 2070242497Sdelphij if (((lba & 0x1fffff) == lba) 2071242497Sdelphij && ((block_count & 0xff) == block_count) 2072242497Sdelphij && (byte2 == 0)) { 2073242497Sdelphij /* We can fit in a 6 byte cdb */ 2074242497Sdelphij struct scsi_rw_6 *scsi_cmd; 2075242497Sdelphij 2076242681Sambrisko scsi_cmd = (struct scsi_rw_6 *)cdb; 2077242497Sdelphij scsi_cmd->opcode = readop ? READ_6 : WRITE_6; 2078242497Sdelphij scsi_ulto3b(lba, scsi_cmd->addr); 2079242497Sdelphij scsi_cmd->length = block_count & 0xff; 2080242497Sdelphij scsi_cmd->control = 0; 2081242497Sdelphij cdb_len = sizeof(*scsi_cmd); 2082242497Sdelphij } else if (((block_count & 0xffff) == block_count) && ((lba & 0xffffffff) == lba)) { 2083242497Sdelphij /* Need a 10 byte CDB */ 2084242497Sdelphij struct scsi_rw_10 *scsi_cmd; 2085242497Sdelphij 2086242681Sambrisko scsi_cmd = (struct scsi_rw_10 *)cdb; 2087242497Sdelphij scsi_cmd->opcode = readop ? READ_10 : WRITE_10; 2088242497Sdelphij scsi_cmd->byte2 = byte2; 2089242497Sdelphij scsi_ulto4b(lba, scsi_cmd->addr); 2090242497Sdelphij scsi_cmd->reserved = 0; 2091242497Sdelphij scsi_ulto2b(block_count, scsi_cmd->length); 2092242497Sdelphij scsi_cmd->control = 0; 2093242497Sdelphij cdb_len = sizeof(*scsi_cmd); 2094242497Sdelphij } else if (((block_count & 0xffffffff) == block_count) && 2095242497Sdelphij ((lba & 0xffffffff) == lba)) { 2096242497Sdelphij /* Block count is too big for 10 byte CDB use a 12 byte CDB */ 2097242497Sdelphij struct scsi_rw_12 *scsi_cmd; 2098242497Sdelphij 2099242681Sambrisko scsi_cmd = (struct scsi_rw_12 *)cdb; 2100242497Sdelphij scsi_cmd->opcode = readop ? READ_12 : WRITE_12; 2101242497Sdelphij scsi_cmd->byte2 = byte2; 2102242497Sdelphij scsi_ulto4b(lba, scsi_cmd->addr); 2103242497Sdelphij scsi_cmd->reserved = 0; 2104242497Sdelphij scsi_ulto4b(block_count, scsi_cmd->length); 2105242497Sdelphij scsi_cmd->control = 0; 2106242497Sdelphij cdb_len = sizeof(*scsi_cmd); 2107242497Sdelphij } else { 2108242497Sdelphij /* 2109242497Sdelphij * 16 byte CDB. We'll only get here if the LBA is larger 2110242497Sdelphij * than 2^32 2111242497Sdelphij */ 2112242497Sdelphij struct scsi_rw_16 *scsi_cmd; 2113242497Sdelphij 2114242681Sambrisko scsi_cmd = (struct scsi_rw_16 *)cdb; 2115242497Sdelphij scsi_cmd->opcode = readop ? READ_16 : WRITE_16; 2116242497Sdelphij scsi_cmd->byte2 = byte2; 2117242497Sdelphij scsi_u64to8b(lba, scsi_cmd->addr); 2118242497Sdelphij scsi_cmd->reserved = 0; 2119242497Sdelphij scsi_ulto4b(block_count, scsi_cmd->length); 2120242497Sdelphij scsi_cmd->control = 0; 2121242497Sdelphij cdb_len = sizeof(*scsi_cmd); 2122242497Sdelphij } 2123242497Sdelphij 2124242497Sdelphij return cdb_len; 2125242497Sdelphij} 2126242497Sdelphij 2127267084Skibextern char *unmapped_buf; 2128267084Skib 2129233711Sambriskostatic struct mfi_command * 2130233711Sambriskomfi_build_syspdio(struct mfi_softc *sc, struct bio *bio) 2131233711Sambrisko{ 2132233711Sambrisko struct mfi_command *cm; 2133233711Sambrisko struct mfi_pass_frame *pass; 2134242681Sambrisko uint32_t context = 0; 2135242681Sambrisko int flags = 0, blkcount = 0, readop; 2136242497Sdelphij uint8_t cdb_len; 2137157114Sscottl 2138247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2139247369Ssmh 2140233711Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 2141233711Sambrisko return (NULL); 2142233711Sambrisko 2143233711Sambrisko /* Zero out the MFI frame */ 2144242681Sambrisko context = cm->cm_frame->header.context; 2145233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2146233711Sambrisko cm->cm_frame->header.context = context; 2147233711Sambrisko pass = &cm->cm_frame->pass; 2148233711Sambrisko bzero(pass->cdb, 16); 2149233711Sambrisko pass->header.cmd = MFI_CMD_PD_SCSI_IO; 2150233711Sambrisko switch (bio->bio_cmd & 0x03) { 2151233711Sambrisko case BIO_READ: 2152267084Skib flags = MFI_CMD_DATAIN | MFI_CMD_BIO; 2153242681Sambrisko readop = 1; 2154233711Sambrisko break; 2155233711Sambrisko case BIO_WRITE: 2156267084Skib flags = MFI_CMD_DATAOUT | MFI_CMD_BIO; 2157242681Sambrisko readop = 0; 2158233711Sambrisko break; 2159233711Sambrisko default: 2160242497Sdelphij /* TODO: what about BIO_DELETE??? */ 2161242681Sambrisko panic("Unsupported bio command %x\n", bio->bio_cmd); 2162233711Sambrisko } 2163233711Sambrisko 2164233711Sambrisko /* Cheat with the sector length to avoid a non-constant division */ 2165242681Sambrisko blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2166233711Sambrisko /* Fill the LBA and Transfer length in CDB */ 2167242681Sambrisko cdb_len = mfi_build_cdb(readop, 0, bio->bio_pblkno, blkcount, 2168242681Sambrisko pass->cdb); 2169233711Sambrisko pass->header.target_id = (uintptr_t)bio->bio_driver1; 2170242681Sambrisko pass->header.lun_id = 0; 2171233711Sambrisko pass->header.timeout = 0; 2172233711Sambrisko pass->header.flags = 0; 2173233711Sambrisko pass->header.scsi_status = 0; 2174233711Sambrisko pass->header.sense_len = MFI_SENSE_LEN; 2175233711Sambrisko pass->header.data_len = bio->bio_bcount; 2176242497Sdelphij pass->header.cdb_len = cdb_len; 2177233711Sambrisko pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2178233711Sambrisko pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2179233711Sambrisko cm->cm_complete = mfi_bio_complete; 2180233711Sambrisko cm->cm_private = bio; 2181267084Skib cm->cm_data = unmapped_buf; 2182233711Sambrisko cm->cm_len = bio->bio_bcount; 2183233711Sambrisko cm->cm_sg = &pass->sgl; 2184233711Sambrisko cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; 2185233711Sambrisko cm->cm_flags = flags; 2186247369Ssmh 2187233711Sambrisko return (cm); 2188233711Sambrisko} 2189233711Sambrisko 2190233711Sambriskostatic struct mfi_command * 2191233711Sambriskomfi_build_ldio(struct mfi_softc *sc, struct bio *bio) 2192233711Sambrisko{ 2193233711Sambrisko struct mfi_io_frame *io; 2194233711Sambrisko struct mfi_command *cm; 2195242497Sdelphij int flags; 2196242497Sdelphij uint32_t blkcount; 2197233711Sambrisko uint32_t context = 0; 2198233711Sambrisko 2199247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2200247369Ssmh 2201233711Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 2202233711Sambrisko return (NULL); 2203233711Sambrisko 2204233711Sambrisko /* Zero out the MFI frame */ 2205233711Sambrisko context = cm->cm_frame->header.context; 2206233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2207233711Sambrisko cm->cm_frame->header.context = context; 2208157114Sscottl io = &cm->cm_frame->io; 2209157114Sscottl switch (bio->bio_cmd & 0x03) { 2210157114Sscottl case BIO_READ: 2211157114Sscottl io->header.cmd = MFI_CMD_LD_READ; 2212267084Skib flags = MFI_CMD_DATAIN | MFI_CMD_BIO; 2213157114Sscottl break; 2214157114Sscottl case BIO_WRITE: 2215157114Sscottl io->header.cmd = MFI_CMD_LD_WRITE; 2216267084Skib flags = MFI_CMD_DATAOUT | MFI_CMD_BIO; 2217157114Sscottl break; 2218157114Sscottl default: 2219242497Sdelphij /* TODO: what about BIO_DELETE??? */ 2220242681Sambrisko panic("Unsupported bio command %x\n", bio->bio_cmd); 2221157114Sscottl } 2222157114Sscottl 2223157114Sscottl /* Cheat with the sector length to avoid a non-constant division */ 2224157114Sscottl blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2225157114Sscottl io->header.target_id = (uintptr_t)bio->bio_driver1; 2226157114Sscottl io->header.timeout = 0; 2227157114Sscottl io->header.flags = 0; 2228233711Sambrisko io->header.scsi_status = 0; 2229157114Sscottl io->header.sense_len = MFI_SENSE_LEN; 2230157114Sscottl io->header.data_len = blkcount; 2231233711Sambrisko io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2232233711Sambrisko io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2233157114Sscottl io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32; 2234157114Sscottl io->lba_lo = bio->bio_pblkno & 0xffffffff; 2235157114Sscottl cm->cm_complete = mfi_bio_complete; 2236157114Sscottl cm->cm_private = bio; 2237267084Skib cm->cm_data = unmapped_buf; 2238157114Sscottl cm->cm_len = bio->bio_bcount; 2239157114Sscottl cm->cm_sg = &io->sgl; 2240157114Sscottl cm->cm_total_frame_size = MFI_IO_FRAME_SIZE; 2241157114Sscottl cm->cm_flags = flags; 2242247369Ssmh 2243157114Sscottl return (cm); 2244157114Sscottl} 2245157114Sscottl 2246157114Sscottlstatic void 2247157114Sscottlmfi_bio_complete(struct mfi_command *cm) 2248157114Sscottl{ 2249157114Sscottl struct bio *bio; 2250157114Sscottl struct mfi_frame_header *hdr; 2251157114Sscottl struct mfi_softc *sc; 2252157114Sscottl 2253157114Sscottl bio = cm->cm_private; 2254157114Sscottl hdr = &cm->cm_frame->header; 2255157114Sscottl sc = cm->cm_sc; 2256157114Sscottl 2257224039Sjhb if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) { 2258157114Sscottl bio->bio_flags |= BIO_ERROR; 2259157114Sscottl bio->bio_error = EIO; 2260247369Ssmh device_printf(sc->mfi_dev, "I/O error, cmd=%p, status=%#x, " 2261247369Ssmh "scsi_status=%#x\n", cm, hdr->cmd_status, hdr->scsi_status); 2262157114Sscottl mfi_print_sense(cm->cm_sc, cm->cm_sense); 2263184897Sambrisko } else if (cm->cm_error != 0) { 2264184897Sambrisko bio->bio_flags |= BIO_ERROR; 2265247369Ssmh bio->bio_error = cm->cm_error; 2266247369Ssmh device_printf(sc->mfi_dev, "I/O error, cmd=%p, error=%#x\n", 2267247369Ssmh cm, cm->cm_error); 2268157114Sscottl } 2269157114Sscottl 2270157114Sscottl mfi_release_command(cm); 2271157114Sscottl mfi_disk_complete(bio); 2272157114Sscottl} 2273157114Sscottl 2274157114Sscottlvoid 2275157114Sscottlmfi_startio(struct mfi_softc *sc) 2276157114Sscottl{ 2277157114Sscottl struct mfi_command *cm; 2278169611Sscottl struct ccb_hdr *ccbh; 2279157114Sscottl 2280157114Sscottl for (;;) { 2281157114Sscottl /* Don't bother if we're short on resources */ 2282157114Sscottl if (sc->mfi_flags & MFI_FLAGS_QFRZN) 2283157114Sscottl break; 2284157114Sscottl 2285157114Sscottl /* Try a command that has already been prepared */ 2286157114Sscottl cm = mfi_dequeue_ready(sc); 2287157114Sscottl 2288169611Sscottl if (cm == NULL) { 2289169611Sscottl if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL) 2290169611Sscottl cm = sc->mfi_cam_start(ccbh); 2291169611Sscottl } 2292169611Sscottl 2293157114Sscottl /* Nope, so look for work on the bioq */ 2294157114Sscottl if (cm == NULL) 2295157114Sscottl cm = mfi_bio_command(sc); 2296157114Sscottl 2297157114Sscottl /* No work available, so exit */ 2298157114Sscottl if (cm == NULL) 2299157114Sscottl break; 2300157114Sscottl 2301157114Sscottl /* Send the command to the controller */ 2302157114Sscottl if (mfi_mapcmd(sc, cm) != 0) { 2303247369Ssmh device_printf(sc->mfi_dev, "Failed to startio\n"); 2304157114Sscottl mfi_requeue_ready(cm); 2305157114Sscottl break; 2306157114Sscottl } 2307157114Sscottl } 2308157114Sscottl} 2309157114Sscottl 2310233711Sambriskoint 2311157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm) 2312157114Sscottl{ 2313157114Sscottl int error, polled; 2314157114Sscottl 2315163398Sscottl mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2316163398Sscottl 2317233711Sambrisko if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) { 2318157114Sscottl polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0; 2319246713Skib if (cm->cm_flags & MFI_CMD_CCB) 2320246713Skib error = bus_dmamap_load_ccb(sc->mfi_buffer_dmat, 2321246713Skib cm->cm_dmamap, cm->cm_data, mfi_data_cb, cm, 2322246713Skib polled); 2323267084Skib else if (cm->cm_flags & MFI_CMD_BIO) 2324267084Skib error = bus_dmamap_load_bio(sc->mfi_buffer_dmat, 2325267084Skib cm->cm_dmamap, cm->cm_private, mfi_data_cb, cm, 2326267084Skib polled); 2327246713Skib else 2328246713Skib error = bus_dmamap_load(sc->mfi_buffer_dmat, 2329246713Skib cm->cm_dmamap, cm->cm_data, cm->cm_len, 2330246713Skib mfi_data_cb, cm, polled); 2331157114Sscottl if (error == EINPROGRESS) { 2332157114Sscottl sc->mfi_flags |= MFI_FLAGS_QFRZN; 2333157114Sscottl return (0); 2334157114Sscottl } 2335157114Sscottl } else { 2336247369Ssmh error = mfi_send_frame(sc, cm); 2337157114Sscottl } 2338157114Sscottl 2339157114Sscottl return (error); 2340157114Sscottl} 2341157114Sscottl 2342157114Sscottlstatic void 2343157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 2344157114Sscottl{ 2345157114Sscottl struct mfi_frame_header *hdr; 2346157114Sscottl struct mfi_command *cm; 2347157237Sscottl union mfi_sgl *sgl; 2348157114Sscottl struct mfi_softc *sc; 2349225869Smav int i, j, first, dir; 2350247369Ssmh int sge_size, locked; 2351157114Sscottl 2352157114Sscottl cm = (struct mfi_command *)arg; 2353157114Sscottl sc = cm->cm_sc; 2354157237Sscottl hdr = &cm->cm_frame->header; 2355157237Sscottl sgl = cm->cm_sg; 2356157114Sscottl 2357247369Ssmh /* 2358247369Ssmh * We need to check if we have the lock as this is async 2359247369Ssmh * callback so even though our caller mfi_mapcmd asserts 2360247369Ssmh * it has the lock, there is no garantee that hasn't been 2361247369Ssmh * dropped if bus_dmamap_load returned prior to our 2362247369Ssmh * completion. 2363247369Ssmh */ 2364247369Ssmh if ((locked = mtx_owned(&sc->mfi_io_lock)) == 0) 2365247369Ssmh mtx_lock(&sc->mfi_io_lock); 2366247369Ssmh 2367170284Sambrisko if (error) { 2368170284Sambrisko printf("error %d in callback\n", error); 2369170284Sambrisko cm->cm_error = error; 2370170284Sambrisko mfi_complete(sc, cm); 2371247369Ssmh goto out; 2372170284Sambrisko } 2373233711Sambrisko /* Use IEEE sgl only for IO's on a SKINNY controller 2374233711Sambrisko * For other commands on a SKINNY controller use either 2375233711Sambrisko * sg32 or sg64 based on the sizeof(bus_addr_t). 2376233711Sambrisko * Also calculate the total frame size based on the type 2377233711Sambrisko * of SGL used. 2378233711Sambrisko */ 2379233711Sambrisko if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) || 2380233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) || 2381233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) && 2382233711Sambrisko (sc->mfi_flags & MFI_FLAGS_SKINNY)) { 2383157237Sscottl for (i = 0; i < nsegs; i++) { 2384233711Sambrisko sgl->sg_skinny[i].addr = segs[i].ds_addr; 2385233711Sambrisko sgl->sg_skinny[i].len = segs[i].ds_len; 2386233711Sambrisko sgl->sg_skinny[i].flag = 0; 2387157114Sscottl } 2388233711Sambrisko hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64; 2389233711Sambrisko sge_size = sizeof(struct mfi_sg_skinny); 2390233711Sambrisko hdr->sg_count = nsegs; 2391157237Sscottl } else { 2392233711Sambrisko j = 0; 2393233711Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 2394233711Sambrisko first = cm->cm_stp_len; 2395233711Sambrisko if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { 2396233711Sambrisko sgl->sg32[j].addr = segs[0].ds_addr; 2397233711Sambrisko sgl->sg32[j++].len = first; 2398233711Sambrisko } else { 2399233711Sambrisko sgl->sg64[j].addr = segs[0].ds_addr; 2400233711Sambrisko sgl->sg64[j++].len = first; 2401233711Sambrisko } 2402233711Sambrisko } else 2403225869Smav first = 0; 2404233711Sambrisko if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { 2405233711Sambrisko for (i = 0; i < nsegs; i++) { 2406233711Sambrisko sgl->sg32[j].addr = segs[i].ds_addr + first; 2407233711Sambrisko sgl->sg32[j++].len = segs[i].ds_len - first; 2408233711Sambrisko first = 0; 2409233711Sambrisko } 2410233711Sambrisko } else { 2411233711Sambrisko for (i = 0; i < nsegs; i++) { 2412233711Sambrisko sgl->sg64[j].addr = segs[i].ds_addr + first; 2413233711Sambrisko sgl->sg64[j++].len = segs[i].ds_len - first; 2414233711Sambrisko first = 0; 2415233711Sambrisko } 2416233711Sambrisko hdr->flags |= MFI_FRAME_SGL64; 2417157237Sscottl } 2418233711Sambrisko hdr->sg_count = j; 2419233711Sambrisko sge_size = sc->mfi_sge_size; 2420157114Sscottl } 2421157114Sscottl 2422157114Sscottl dir = 0; 2423157114Sscottl if (cm->cm_flags & MFI_CMD_DATAIN) { 2424157114Sscottl dir |= BUS_DMASYNC_PREREAD; 2425157114Sscottl hdr->flags |= MFI_FRAME_DIR_READ; 2426157114Sscottl } 2427157114Sscottl if (cm->cm_flags & MFI_CMD_DATAOUT) { 2428157114Sscottl dir |= BUS_DMASYNC_PREWRITE; 2429157114Sscottl hdr->flags |= MFI_FRAME_DIR_WRITE; 2430157114Sscottl } 2431157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir); 2432157114Sscottl cm->cm_flags |= MFI_CMD_MAPPED; 2433157114Sscottl 2434157114Sscottl /* 2435157114Sscottl * Instead of calculating the total number of frames in the 2436157114Sscottl * compound frame, it's already assumed that there will be at 2437157114Sscottl * least 1 frame, so don't compensate for the modulo of the 2438157114Sscottl * following division. 2439157114Sscottl */ 2440162458Sscottl cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs); 2441157114Sscottl cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; 2442157114Sscottl 2443247369Ssmh if ((error = mfi_send_frame(sc, cm)) != 0) { 2444247369Ssmh printf("error %d in callback from mfi_send_frame\n", error); 2445247369Ssmh cm->cm_error = error; 2446247369Ssmh mfi_complete(sc, cm); 2447247369Ssmh goto out; 2448247369Ssmh } 2449157114Sscottl 2450247369Ssmhout: 2451247369Ssmh /* leave the lock in the state we found it */ 2452247369Ssmh if (locked == 0) 2453247369Ssmh mtx_unlock(&sc->mfi_io_lock); 2454247369Ssmh 2455157114Sscottl return; 2456157114Sscottl} 2457157114Sscottl 2458157114Sscottlstatic int 2459157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm) 2460157114Sscottl{ 2461247369Ssmh int error; 2462247369Ssmh 2463247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2464247369Ssmh 2465247369Ssmh if (sc->MFA_enabled) 2466247369Ssmh error = mfi_tbolt_send_frame(sc, cm); 2467247369Ssmh else 2468247369Ssmh error = mfi_std_send_frame(sc, cm); 2469247369Ssmh 2470247369Ssmh if (error != 0 && (cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0) 2471247369Ssmh mfi_remove_busy(cm); 2472247369Ssmh 2473247369Ssmh return (error); 2474247369Ssmh} 2475247369Ssmh 2476247369Ssmhstatic int 2477247369Ssmhmfi_std_send_frame(struct mfi_softc *sc, struct mfi_command *cm) 2478247369Ssmh{ 2479164375Sscottl struct mfi_frame_header *hdr; 2480247369Ssmh int tm = mfi_polled_cmd_timeout * 1000; 2481157114Sscottl 2482164375Sscottl hdr = &cm->cm_frame->header; 2483164375Sscottl 2484164375Sscottl if ((cm->cm_flags & MFI_CMD_POLLED) == 0) { 2485164375Sscottl cm->cm_timestamp = time_uptime; 2486164375Sscottl mfi_enqueue_busy(cm); 2487164375Sscottl } else { 2488224039Sjhb hdr->cmd_status = MFI_STAT_INVALID_STATUS; 2489164375Sscottl hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 2490164375Sscottl } 2491164375Sscottl 2492157114Sscottl /* 2493157114Sscottl * The bus address of the command is aligned on a 64 byte boundary, 2494157114Sscottl * leaving the least 6 bits as zero. For whatever reason, the 2495157114Sscottl * hardware wants the address shifted right by three, leaving just 2496162458Sscottl * 3 zero bits. These three bits are then used as a prefetching 2497162458Sscottl * hint for the hardware to predict how many frames need to be 2498162458Sscottl * fetched across the bus. If a command has more than 8 frames 2499162458Sscottl * then the 3 bits are set to 0x7 and the firmware uses other 2500162458Sscottl * information in the command to determine the total amount to fetch. 2501162458Sscottl * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames 2502162458Sscottl * is enough for both 32bit and 64bit systems. 2503157114Sscottl */ 2504162458Sscottl if (cm->cm_extra_frames > 7) 2505162458Sscottl cm->cm_extra_frames = 7; 2506162458Sscottl 2507233711Sambrisko sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames); 2508164375Sscottl 2509164375Sscottl if ((cm->cm_flags & MFI_CMD_POLLED) == 0) 2510164375Sscottl return (0); 2511164375Sscottl 2512164375Sscottl /* This is a polled command, so busy-wait for it to complete. */ 2513224039Sjhb while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 2514164375Sscottl DELAY(1000); 2515165225Sambrisko tm -= 1; 2516164375Sscottl if (tm <= 0) 2517164375Sscottl break; 2518164375Sscottl } 2519164375Sscottl 2520224039Sjhb if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 2521165225Sambrisko device_printf(sc->mfi_dev, "Frame %p timed out " 2522233711Sambrisko "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode); 2523164375Sscottl return (ETIMEDOUT); 2524164375Sscottl } 2525164375Sscottl 2526157114Sscottl return (0); 2527157114Sscottl} 2528157114Sscottl 2529233711Sambrisko 2530233711Sambriskovoid 2531157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm) 2532157114Sscottl{ 2533157114Sscottl int dir; 2534247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2535157114Sscottl 2536157114Sscottl if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) { 2537157114Sscottl dir = 0; 2538225869Smav if ((cm->cm_flags & MFI_CMD_DATAIN) || 2539225869Smav (cm->cm_frame->header.cmd == MFI_CMD_STP)) 2540157114Sscottl dir |= BUS_DMASYNC_POSTREAD; 2541157114Sscottl if (cm->cm_flags & MFI_CMD_DATAOUT) 2542157114Sscottl dir |= BUS_DMASYNC_POSTWRITE; 2543157114Sscottl 2544157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir); 2545157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2546157114Sscottl cm->cm_flags &= ~MFI_CMD_MAPPED; 2547157114Sscottl } 2548157114Sscottl 2549170284Sambrisko cm->cm_flags |= MFI_CMD_COMPLETED; 2550170284Sambrisko 2551157114Sscottl if (cm->cm_complete != NULL) 2552157114Sscottl cm->cm_complete(cm); 2553159811Sps else 2554159811Sps wakeup(cm); 2555157114Sscottl} 2556157114Sscottl 2557158737Sambriskostatic int 2558242681Sambriskomfi_abort(struct mfi_softc *sc, struct mfi_command **cm_abort) 2559158737Sambrisko{ 2560158737Sambrisko struct mfi_command *cm; 2561158737Sambrisko struct mfi_abort_frame *abort; 2562247369Ssmh int i = 0, error; 2563233711Sambrisko uint32_t context = 0; 2564158737Sambrisko 2565242681Sambrisko mtx_lock(&sc->mfi_io_lock); 2566158737Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 2567247369Ssmh mtx_unlock(&sc->mfi_io_lock); 2568158737Sambrisko return (EBUSY); 2569158737Sambrisko } 2570158737Sambrisko 2571233711Sambrisko /* Zero out the MFI frame */ 2572233711Sambrisko context = cm->cm_frame->header.context; 2573233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2574233711Sambrisko cm->cm_frame->header.context = context; 2575233711Sambrisko 2576158737Sambrisko abort = &cm->cm_frame->abort; 2577158737Sambrisko abort->header.cmd = MFI_CMD_ABORT; 2578158737Sambrisko abort->header.flags = 0; 2579233711Sambrisko abort->header.scsi_status = 0; 2580242681Sambrisko abort->abort_context = (*cm_abort)->cm_frame->header.context; 2581242681Sambrisko abort->abort_mfi_addr_lo = (uint32_t)(*cm_abort)->cm_frame_busaddr; 2582233711Sambrisko abort->abort_mfi_addr_hi = 2583242681Sambrisko (uint32_t)((uint64_t)(*cm_abort)->cm_frame_busaddr >> 32); 2584158737Sambrisko cm->cm_data = NULL; 2585164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 2586158737Sambrisko 2587247369Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) 2588247369Ssmh device_printf(sc->mfi_dev, "failed to abort command\n"); 2589158737Sambrisko mfi_release_command(cm); 2590158737Sambrisko 2591242681Sambrisko mtx_unlock(&sc->mfi_io_lock); 2592242681Sambrisko while (i < 5 && *cm_abort != NULL) { 2593242681Sambrisko tsleep(cm_abort, 0, "mfiabort", 2594233711Sambrisko 5 * hz); 2595165225Sambrisko i++; 2596158737Sambrisko } 2597242681Sambrisko if (*cm_abort != NULL) { 2598242681Sambrisko /* Force a complete if command didn't abort */ 2599242681Sambrisko mtx_lock(&sc->mfi_io_lock); 2600242681Sambrisko (*cm_abort)->cm_complete(*cm_abort); 2601242681Sambrisko mtx_unlock(&sc->mfi_io_lock); 2602235014Sambrisko } 2603158737Sambrisko 2604247369Ssmh return (error); 2605158737Sambrisko} 2606158737Sambrisko 2607157114Sscottlint 2608233711Sambriskomfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, 2609233711Sambrisko int len) 2610157114Sscottl{ 2611157114Sscottl struct mfi_command *cm; 2612157114Sscottl struct mfi_io_frame *io; 2613157114Sscottl int error; 2614233711Sambrisko uint32_t context = 0; 2615157114Sscottl 2616157114Sscottl if ((cm = mfi_dequeue_free(sc)) == NULL) 2617157114Sscottl return (EBUSY); 2618157114Sscottl 2619233711Sambrisko /* Zero out the MFI frame */ 2620233711Sambrisko context = cm->cm_frame->header.context; 2621233711Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2622233711Sambrisko cm->cm_frame->header.context = context; 2623233711Sambrisko 2624157114Sscottl io = &cm->cm_frame->io; 2625157114Sscottl io->header.cmd = MFI_CMD_LD_WRITE; 2626157114Sscottl io->header.target_id = id; 2627157114Sscottl io->header.timeout = 0; 2628157114Sscottl io->header.flags = 0; 2629233711Sambrisko io->header.scsi_status = 0; 2630157114Sscottl io->header.sense_len = MFI_SENSE_LEN; 2631157114Sscottl io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2632233711Sambrisko io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2633233711Sambrisko io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2634157114Sscottl io->lba_hi = (lba & 0xffffffff00000000) >> 32; 2635157114Sscottl io->lba_lo = lba & 0xffffffff; 2636157114Sscottl cm->cm_data = virt; 2637157114Sscottl cm->cm_len = len; 2638157114Sscottl cm->cm_sg = &io->sgl; 2639157114Sscottl cm->cm_total_frame_size = MFI_IO_FRAME_SIZE; 2640157114Sscottl cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT; 2641157114Sscottl 2642247369Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) 2643247369Ssmh device_printf(sc->mfi_dev, "failed dump blocks\n"); 2644157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 2645157114Sscottl BUS_DMASYNC_POSTWRITE); 2646157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2647157114Sscottl mfi_release_command(cm); 2648157114Sscottl 2649157114Sscottl return (error); 2650157114Sscottl} 2651157114Sscottl 2652233711Sambriskoint 2653233711Sambriskomfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, 2654233711Sambrisko int len) 2655233711Sambrisko{ 2656233711Sambrisko struct mfi_command *cm; 2657233711Sambrisko struct mfi_pass_frame *pass; 2658242681Sambrisko int error, readop, cdb_len; 2659242497Sdelphij uint32_t blkcount; 2660233711Sambrisko 2661233711Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 2662233711Sambrisko return (EBUSY); 2663233711Sambrisko 2664233711Sambrisko pass = &cm->cm_frame->pass; 2665233711Sambrisko bzero(pass->cdb, 16); 2666233711Sambrisko pass->header.cmd = MFI_CMD_PD_SCSI_IO; 2667242681Sambrisko 2668242681Sambrisko readop = 0; 2669233711Sambrisko blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2670242681Sambrisko cdb_len = mfi_build_cdb(readop, 0, lba, blkcount, pass->cdb); 2671233711Sambrisko pass->header.target_id = id; 2672233711Sambrisko pass->header.timeout = 0; 2673233711Sambrisko pass->header.flags = 0; 2674233711Sambrisko pass->header.scsi_status = 0; 2675233711Sambrisko pass->header.sense_len = MFI_SENSE_LEN; 2676233711Sambrisko pass->header.data_len = len; 2677242681Sambrisko pass->header.cdb_len = cdb_len; 2678233711Sambrisko pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2679233711Sambrisko pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2680233711Sambrisko cm->cm_data = virt; 2681233711Sambrisko cm->cm_len = len; 2682233711Sambrisko cm->cm_sg = &pass->sgl; 2683233711Sambrisko cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; 2684242681Sambrisko cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT | MFI_CMD_SCSI; 2685233711Sambrisko 2686247369Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) 2687247369Ssmh device_printf(sc->mfi_dev, "failed dump blocks\n"); 2688233711Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 2689233711Sambrisko BUS_DMASYNC_POSTWRITE); 2690233711Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2691233711Sambrisko mfi_release_command(cm); 2692233711Sambrisko 2693233711Sambrisko return (error); 2694233711Sambrisko} 2695233711Sambrisko 2696157114Sscottlstatic int 2697192450Simpmfi_open(struct cdev *dev, int flags, int fmt, struct thread *td) 2698157114Sscottl{ 2699157114Sscottl struct mfi_softc *sc; 2700171822Sjhb int error; 2701157114Sscottl 2702157114Sscottl sc = dev->si_drv1; 2703163398Sscottl 2704163398Sscottl mtx_lock(&sc->mfi_io_lock); 2705171822Sjhb if (sc->mfi_detaching) 2706171822Sjhb error = ENXIO; 2707171822Sjhb else { 2708171822Sjhb sc->mfi_flags |= MFI_FLAGS_OPEN; 2709171822Sjhb error = 0; 2710171822Sjhb } 2711163398Sscottl mtx_unlock(&sc->mfi_io_lock); 2712157114Sscottl 2713171822Sjhb return (error); 2714157114Sscottl} 2715157114Sscottl 2716157114Sscottlstatic int 2717192450Simpmfi_close(struct cdev *dev, int flags, int fmt, struct thread *td) 2718157114Sscottl{ 2719157114Sscottl struct mfi_softc *sc; 2720163398Sscottl struct mfi_aen *mfi_aen_entry, *tmp; 2721157114Sscottl 2722157114Sscottl sc = dev->si_drv1; 2723163398Sscottl 2724163398Sscottl mtx_lock(&sc->mfi_io_lock); 2725157114Sscottl sc->mfi_flags &= ~MFI_FLAGS_OPEN; 2726157114Sscottl 2727163398Sscottl TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) { 2728158737Sambrisko if (mfi_aen_entry->p == curproc) { 2729158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 2730158737Sambrisko aen_link); 2731158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 2732158737Sambrisko } 2733158737Sambrisko } 2734163398Sscottl mtx_unlock(&sc->mfi_io_lock); 2735157114Sscottl return (0); 2736157114Sscottl} 2737157114Sscottl 2738157114Sscottlstatic int 2739171821Sjhbmfi_config_lock(struct mfi_softc *sc, uint32_t opcode) 2740171821Sjhb{ 2741171821Sjhb 2742171821Sjhb switch (opcode) { 2743171821Sjhb case MFI_DCMD_LD_DELETE: 2744171821Sjhb case MFI_DCMD_CFG_ADD: 2745171821Sjhb case MFI_DCMD_CFG_CLEAR: 2746240962Sjhb case MFI_DCMD_CFG_FOREIGN_IMPORT: 2747171821Sjhb sx_xlock(&sc->mfi_config_lock); 2748171821Sjhb return (1); 2749171821Sjhb default: 2750171821Sjhb return (0); 2751171821Sjhb } 2752171821Sjhb} 2753171821Sjhb 2754171821Sjhbstatic void 2755171821Sjhbmfi_config_unlock(struct mfi_softc *sc, int locked) 2756171821Sjhb{ 2757171821Sjhb 2758171821Sjhb if (locked) 2759171821Sjhb sx_xunlock(&sc->mfi_config_lock); 2760171821Sjhb} 2761171821Sjhb 2762233711Sambrisko/* 2763233711Sambrisko * Perform pre-issue checks on commands from userland and possibly veto 2764233711Sambrisko * them. 2765233711Sambrisko */ 2766171821Sjhbstatic int 2767171821Sjhbmfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm) 2768171821Sjhb{ 2769171821Sjhb struct mfi_disk *ld, *ld2; 2770171821Sjhb int error; 2771233711Sambrisko struct mfi_system_pd *syspd = NULL; 2772233711Sambrisko uint16_t syspd_id; 2773233711Sambrisko uint16_t *mbox; 2774171821Sjhb 2775171821Sjhb mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2776171821Sjhb error = 0; 2777171821Sjhb switch (cm->cm_frame->dcmd.opcode) { 2778171821Sjhb case MFI_DCMD_LD_DELETE: 2779171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2780171821Sjhb if (ld->ld_id == cm->cm_frame->dcmd.mbox[0]) 2781171821Sjhb break; 2782171821Sjhb } 2783171821Sjhb if (ld == NULL) 2784171821Sjhb error = ENOENT; 2785171821Sjhb else 2786171821Sjhb error = mfi_disk_disable(ld); 2787171821Sjhb break; 2788171821Sjhb case MFI_DCMD_CFG_CLEAR: 2789171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2790171821Sjhb error = mfi_disk_disable(ld); 2791171821Sjhb if (error) 2792171821Sjhb break; 2793171821Sjhb } 2794171821Sjhb if (error) { 2795171821Sjhb TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) { 2796171821Sjhb if (ld2 == ld) 2797171821Sjhb break; 2798171821Sjhb mfi_disk_enable(ld2); 2799171821Sjhb } 2800171821Sjhb } 2801171821Sjhb break; 2802233711Sambrisko case MFI_DCMD_PD_STATE_SET: 2803233711Sambrisko mbox = (uint16_t *) cm->cm_frame->dcmd.mbox; 2804233711Sambrisko syspd_id = mbox[0]; 2805233711Sambrisko if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { 2806233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { 2807233711Sambrisko if (syspd->pd_id == syspd_id) 2808233711Sambrisko break; 2809233711Sambrisko } 2810233711Sambrisko } 2811233711Sambrisko else 2812233711Sambrisko break; 2813233711Sambrisko if (syspd) 2814233711Sambrisko error = mfi_syspd_disable(syspd); 2815233711Sambrisko break; 2816171821Sjhb default: 2817171821Sjhb break; 2818171821Sjhb } 2819171821Sjhb return (error); 2820171821Sjhb} 2821171821Sjhb 2822171821Sjhb/* Perform post-issue checks on commands from userland. */ 2823171821Sjhbstatic void 2824171821Sjhbmfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm) 2825171821Sjhb{ 2826171821Sjhb struct mfi_disk *ld, *ldn; 2827233711Sambrisko struct mfi_system_pd *syspd = NULL; 2828233711Sambrisko uint16_t syspd_id; 2829233711Sambrisko uint16_t *mbox; 2830171821Sjhb 2831171821Sjhb switch (cm->cm_frame->dcmd.opcode) { 2832171821Sjhb case MFI_DCMD_LD_DELETE: 2833171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2834171821Sjhb if (ld->ld_id == cm->cm_frame->dcmd.mbox[0]) 2835171821Sjhb break; 2836171821Sjhb } 2837171821Sjhb KASSERT(ld != NULL, ("volume dissappeared")); 2838171821Sjhb if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { 2839171821Sjhb mtx_unlock(&sc->mfi_io_lock); 2840196403Sjhb mtx_lock(&Giant); 2841171821Sjhb device_delete_child(sc->mfi_dev, ld->ld_dev); 2842196403Sjhb mtx_unlock(&Giant); 2843171821Sjhb mtx_lock(&sc->mfi_io_lock); 2844171821Sjhb } else 2845171821Sjhb mfi_disk_enable(ld); 2846171821Sjhb break; 2847171821Sjhb case MFI_DCMD_CFG_CLEAR: 2848171821Sjhb if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { 2849171821Sjhb mtx_unlock(&sc->mfi_io_lock); 2850196403Sjhb mtx_lock(&Giant); 2851171821Sjhb TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) { 2852171821Sjhb device_delete_child(sc->mfi_dev, ld->ld_dev); 2853171821Sjhb } 2854196403Sjhb mtx_unlock(&Giant); 2855171821Sjhb mtx_lock(&sc->mfi_io_lock); 2856171821Sjhb } else { 2857171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) 2858171821Sjhb mfi_disk_enable(ld); 2859171821Sjhb } 2860171821Sjhb break; 2861171821Sjhb case MFI_DCMD_CFG_ADD: 2862171821Sjhb mfi_ldprobe(sc); 2863171821Sjhb break; 2864184897Sambrisko case MFI_DCMD_CFG_FOREIGN_IMPORT: 2865184897Sambrisko mfi_ldprobe(sc); 2866184897Sambrisko break; 2867233711Sambrisko case MFI_DCMD_PD_STATE_SET: 2868233711Sambrisko mbox = (uint16_t *) cm->cm_frame->dcmd.mbox; 2869233711Sambrisko syspd_id = mbox[0]; 2870233711Sambrisko if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { 2871233711Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) { 2872233711Sambrisko if (syspd->pd_id == syspd_id) 2873233711Sambrisko break; 2874233711Sambrisko } 2875233711Sambrisko } 2876233711Sambrisko else 2877233711Sambrisko break; 2878233711Sambrisko /* If the transition fails then enable the syspd again */ 2879233711Sambrisko if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK) 2880233711Sambrisko mfi_syspd_enable(syspd); 2881233711Sambrisko break; 2882171821Sjhb } 2883171821Sjhb} 2884171821Sjhb 2885242681Sambriskostatic int 2886242681Sambriskomfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm) 2887233711Sambrisko{ 2888242681Sambrisko struct mfi_config_data *conf_data; 2889233711Sambrisko struct mfi_command *ld_cm = NULL; 2890233711Sambrisko struct mfi_ld_info *ld_info = NULL; 2891242681Sambrisko struct mfi_ld_config *ld; 2892242681Sambrisko char *p; 2893233711Sambrisko int error = 0; 2894233711Sambrisko 2895242681Sambrisko conf_data = (struct mfi_config_data *)cm->cm_data; 2896242681Sambrisko 2897242681Sambrisko if (cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) { 2898242681Sambrisko p = (char *)conf_data->array; 2899242681Sambrisko p += conf_data->array_size * conf_data->array_count; 2900242681Sambrisko ld = (struct mfi_ld_config *)p; 2901242681Sambrisko if (ld->params.isSSCD == 1) 2902242681Sambrisko error = 1; 2903233711Sambrisko } else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) { 2904233711Sambrisko error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO, 2905233711Sambrisko (void **)&ld_info, sizeof(*ld_info)); 2906235016Sambrisko if (error) { 2907233711Sambrisko device_printf(sc->mfi_dev, "Failed to allocate" 2908233711Sambrisko "MFI_DCMD_LD_GET_INFO %d", error); 2909233711Sambrisko if (ld_info) 2910233711Sambrisko free(ld_info, M_MFIBUF); 2911233711Sambrisko return 0; 2912233711Sambrisko } 2913233711Sambrisko ld_cm->cm_flags = MFI_CMD_DATAIN; 2914233711Sambrisko ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0]; 2915233711Sambrisko ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0]; 2916235016Sambrisko if (mfi_wait_command(sc, ld_cm) != 0) { 2917233711Sambrisko device_printf(sc->mfi_dev, "failed to get log drv\n"); 2918233711Sambrisko mfi_release_command(ld_cm); 2919233711Sambrisko free(ld_info, M_MFIBUF); 2920233711Sambrisko return 0; 2921233711Sambrisko } 2922233711Sambrisko 2923233711Sambrisko if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) { 2924233711Sambrisko free(ld_info, M_MFIBUF); 2925233711Sambrisko mfi_release_command(ld_cm); 2926233711Sambrisko return 0; 2927233711Sambrisko } 2928233711Sambrisko else 2929233711Sambrisko ld_info = (struct mfi_ld_info *)ld_cm->cm_private; 2930233711Sambrisko 2931233711Sambrisko if (ld_info->ld_config.params.isSSCD == 1) 2932233711Sambrisko error = 1; 2933233711Sambrisko 2934233711Sambrisko mfi_release_command(ld_cm); 2935233711Sambrisko free(ld_info, M_MFIBUF); 2936233711Sambrisko 2937233711Sambrisko } 2938233711Sambrisko return error; 2939233711Sambrisko} 2940233711Sambrisko 2941171821Sjhbstatic int 2942233711Sambriskomfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg) 2943233711Sambrisko{ 2944233711Sambrisko uint8_t i; 2945233711Sambrisko struct mfi_ioc_packet *ioc; 2946233711Sambrisko ioc = (struct mfi_ioc_packet *)arg; 2947233711Sambrisko int sge_size, error; 2948233711Sambrisko struct megasas_sge *kern_sge; 2949233711Sambrisko 2950233711Sambrisko memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr)); 2951233711Sambrisko kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off); 2952233711Sambrisko cm->cm_frame->header.sg_count = ioc->mfi_sge_count; 2953233711Sambrisko 2954233711Sambrisko if (sizeof(bus_addr_t) == 8) { 2955233711Sambrisko cm->cm_frame->header.flags |= MFI_FRAME_SGL64; 2956233711Sambrisko cm->cm_extra_frames = 2; 2957233711Sambrisko sge_size = sizeof(struct mfi_sg64); 2958233711Sambrisko } else { 2959233711Sambrisko cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; 2960233711Sambrisko sge_size = sizeof(struct mfi_sg32); 2961233711Sambrisko } 2962233711Sambrisko 2963233711Sambrisko cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count); 2964233711Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 2965233711Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 2966233711Sambrisko 1, 0, /* algnmnt, boundary */ 2967233711Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 2968233711Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 2969233711Sambrisko NULL, NULL, /* filter, filterarg */ 2970233711Sambrisko ioc->mfi_sgl[i].iov_len,/* maxsize */ 2971233711Sambrisko 2, /* nsegments */ 2972233711Sambrisko ioc->mfi_sgl[i].iov_len,/* maxsegsize */ 2973233711Sambrisko BUS_DMA_ALLOCNOW, /* flags */ 2974233711Sambrisko NULL, NULL, /* lockfunc, lockarg */ 2975233711Sambrisko &sc->mfi_kbuff_arr_dmat[i])) { 2976233711Sambrisko device_printf(sc->mfi_dev, 2977233711Sambrisko "Cannot allocate mfi_kbuff_arr_dmat tag\n"); 2978233711Sambrisko return (ENOMEM); 2979233711Sambrisko } 2980233711Sambrisko 2981233711Sambrisko if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i], 2982233711Sambrisko (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT, 2983233711Sambrisko &sc->mfi_kbuff_arr_dmamap[i])) { 2984233711Sambrisko device_printf(sc->mfi_dev, 2985233711Sambrisko "Cannot allocate mfi_kbuff_arr_dmamap memory\n"); 2986233711Sambrisko return (ENOMEM); 2987233711Sambrisko } 2988233711Sambrisko 2989233711Sambrisko bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i], 2990233711Sambrisko sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i], 2991233711Sambrisko ioc->mfi_sgl[i].iov_len, mfi_addr_cb, 2992233711Sambrisko &sc->mfi_kbuff_arr_busaddr[i], 0); 2993233711Sambrisko 2994233711Sambrisko if (!sc->kbuff_arr[i]) { 2995233711Sambrisko device_printf(sc->mfi_dev, 2996233711Sambrisko "Could not allocate memory for kbuff_arr info\n"); 2997233711Sambrisko return -1; 2998233711Sambrisko } 2999233711Sambrisko kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i]; 3000233711Sambrisko kern_sge[i].length = ioc->mfi_sgl[i].iov_len; 3001233711Sambrisko 3002233711Sambrisko if (sizeof(bus_addr_t) == 8) { 3003233711Sambrisko cm->cm_frame->stp.sgl.sg64[i].addr = 3004233711Sambrisko kern_sge[i].phys_addr; 3005233711Sambrisko cm->cm_frame->stp.sgl.sg64[i].len = 3006233711Sambrisko ioc->mfi_sgl[i].iov_len; 3007233711Sambrisko } else { 3008247594Sdelphij cm->cm_frame->stp.sgl.sg32[i].addr = 3009233711Sambrisko kern_sge[i].phys_addr; 3010233711Sambrisko cm->cm_frame->stp.sgl.sg32[i].len = 3011233711Sambrisko ioc->mfi_sgl[i].iov_len; 3012233711Sambrisko } 3013233711Sambrisko 3014233711Sambrisko error = copyin(ioc->mfi_sgl[i].iov_base, 3015233711Sambrisko sc->kbuff_arr[i], 3016233711Sambrisko ioc->mfi_sgl[i].iov_len); 3017233711Sambrisko if (error != 0) { 3018233711Sambrisko device_printf(sc->mfi_dev, "Copy in failed\n"); 3019233711Sambrisko return error; 3020233711Sambrisko } 3021233711Sambrisko } 3022233711Sambrisko 3023233711Sambrisko cm->cm_flags |=MFI_CMD_MAPPED; 3024233711Sambrisko return 0; 3025233711Sambrisko} 3026233711Sambrisko 3027233711Sambriskostatic int 3028178968Sscottlmfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc) 3029178968Sscottl{ 3030178968Sscottl struct mfi_command *cm; 3031178968Sscottl struct mfi_dcmd_frame *dcmd; 3032178968Sscottl void *ioc_buf = NULL; 3033178968Sscottl uint32_t context; 3034178968Sscottl int error = 0, locked; 3035178968Sscottl 3036178968Sscottl 3037178968Sscottl if (ioc->buf_size > 0) { 3038238077Sjhb if (ioc->buf_size > 1024 * 1024) 3039238077Sjhb return (ENOMEM); 3040178968Sscottl ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK); 3041178968Sscottl error = copyin(ioc->buf, ioc_buf, ioc->buf_size); 3042178968Sscottl if (error) { 3043178968Sscottl device_printf(sc->mfi_dev, "failed to copyin\n"); 3044178968Sscottl free(ioc_buf, M_MFIBUF); 3045178968Sscottl return (error); 3046178968Sscottl } 3047178968Sscottl } 3048178968Sscottl 3049178968Sscottl locked = mfi_config_lock(sc, ioc->ioc_frame.opcode); 3050178968Sscottl 3051178968Sscottl mtx_lock(&sc->mfi_io_lock); 3052178968Sscottl while ((cm = mfi_dequeue_free(sc)) == NULL) 3053178968Sscottl msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz); 3054178968Sscottl 3055178968Sscottl /* Save context for later */ 3056178968Sscottl context = cm->cm_frame->header.context; 3057178968Sscottl 3058178968Sscottl dcmd = &cm->cm_frame->dcmd; 3059178968Sscottl bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame)); 3060178968Sscottl 3061178968Sscottl cm->cm_sg = &dcmd->sgl; 3062178968Sscottl cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 3063178968Sscottl cm->cm_data = ioc_buf; 3064178968Sscottl cm->cm_len = ioc->buf_size; 3065178968Sscottl 3066178968Sscottl /* restore context */ 3067178968Sscottl cm->cm_frame->header.context = context; 3068178968Sscottl 3069178968Sscottl /* Cheat since we don't know if we're writing or reading */ 3070178968Sscottl cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT; 3071178968Sscottl 3072178968Sscottl error = mfi_check_command_pre(sc, cm); 3073178968Sscottl if (error) 3074178968Sscottl goto out; 3075178968Sscottl 3076178968Sscottl error = mfi_wait_command(sc, cm); 3077178968Sscottl if (error) { 3078178968Sscottl device_printf(sc->mfi_dev, "ioctl failed %d\n", error); 3079178968Sscottl goto out; 3080178968Sscottl } 3081178968Sscottl bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame)); 3082178968Sscottl mfi_check_command_post(sc, cm); 3083178968Sscottlout: 3084178968Sscottl mfi_release_command(cm); 3085178968Sscottl mtx_unlock(&sc->mfi_io_lock); 3086178968Sscottl mfi_config_unlock(sc, locked); 3087178968Sscottl if (ioc->buf_size > 0) 3088178968Sscottl error = copyout(ioc_buf, ioc->buf, ioc->buf_size); 3089178968Sscottl if (ioc_buf) 3090178968Sscottl free(ioc_buf, M_MFIBUF); 3091178968Sscottl return (error); 3092178968Sscottl} 3093178968Sscottl 3094178968Sscottl#define PTRIN(p) ((void *)(uintptr_t)(p)) 3095178968Sscottl 3096178968Sscottlstatic int 3097192450Simpmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 3098157114Sscottl{ 3099157114Sscottl struct mfi_softc *sc; 3100157114Sscottl union mfi_statrequest *ms; 3101164281Sambrisko struct mfi_ioc_packet *ioc; 3102233711Sambrisko#ifdef COMPAT_FREEBSD32 3103179392Sambrisko struct mfi_ioc_packet32 *ioc32; 3104179392Sambrisko#endif 3105164281Sambrisko struct mfi_ioc_aen *aen; 3106164281Sambrisko struct mfi_command *cm = NULL; 3107233711Sambrisko uint32_t context = 0; 3108184897Sambrisko union mfi_sense_ptr sense_ptr; 3109233711Sambrisko uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0; 3110225869Smav size_t len; 3111233711Sambrisko int i, res; 3112178968Sscottl struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg; 3113233711Sambrisko#ifdef COMPAT_FREEBSD32 3114178968Sscottl struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg; 3115178968Sscottl struct mfi_ioc_passthru iop_swab; 3116178968Sscottl#endif 3117171821Sjhb int error, locked; 3118233711Sambrisko union mfi_sgl *sgl; 3119157114Sscottl sc = dev->si_drv1; 3120157114Sscottl error = 0; 3121157114Sscottl 3122233711Sambrisko if (sc->adpreset) 3123233711Sambrisko return EBUSY; 3124233711Sambrisko 3125233711Sambrisko if (sc->hw_crit_error) 3126233711Sambrisko return EBUSY; 3127233711Sambrisko 3128233711Sambrisko if (sc->issuepend_done == 0) 3129233711Sambrisko return EBUSY; 3130233711Sambrisko 3131157114Sscottl switch (cmd) { 3132157114Sscottl case MFIIO_STATS: 3133157114Sscottl ms = (union mfi_statrequest *)arg; 3134157114Sscottl switch (ms->ms_item) { 3135157114Sscottl case MFIQ_FREE: 3136157114Sscottl case MFIQ_BIO: 3137157114Sscottl case MFIQ_READY: 3138157114Sscottl case MFIQ_BUSY: 3139157114Sscottl bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat, 3140157114Sscottl sizeof(struct mfi_qstat)); 3141157114Sscottl break; 3142157114Sscottl default: 3143158737Sambrisko error = ENOIOCTL; 3144157114Sscottl break; 3145157114Sscottl } 3146157114Sscottl break; 3147169451Sscottl case MFIIO_QUERY_DISK: 3148169451Sscottl { 3149169451Sscottl struct mfi_query_disk *qd; 3150169451Sscottl struct mfi_disk *ld; 3151169451Sscottl 3152169451Sscottl qd = (struct mfi_query_disk *)arg; 3153169451Sscottl mtx_lock(&sc->mfi_io_lock); 3154169451Sscottl TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 3155169451Sscottl if (ld->ld_id == qd->array_id) 3156169451Sscottl break; 3157169451Sscottl } 3158169451Sscottl if (ld == NULL) { 3159169451Sscottl qd->present = 0; 3160169451Sscottl mtx_unlock(&sc->mfi_io_lock); 3161169451Sscottl return (0); 3162169451Sscottl } 3163169451Sscottl qd->present = 1; 3164169451Sscottl if (ld->ld_flags & MFI_DISK_FLAGS_OPEN) 3165169451Sscottl qd->open = 1; 3166169451Sscottl bzero(qd->devname, SPECNAMELEN + 1); 3167169451Sscottl snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit); 3168169451Sscottl mtx_unlock(&sc->mfi_io_lock); 3169169451Sscottl break; 3170169451Sscottl } 3171164281Sambrisko case MFI_CMD: 3172233711Sambrisko#ifdef COMPAT_FREEBSD32 3173179392Sambrisko case MFI_CMD32: 3174179392Sambrisko#endif 3175177489Sambrisko { 3176177489Sambrisko devclass_t devclass; 3177164281Sambrisko ioc = (struct mfi_ioc_packet *)arg; 3178177489Sambrisko int adapter; 3179164281Sambrisko 3180177489Sambrisko adapter = ioc->mfi_adapter_no; 3181177489Sambrisko if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) { 3182177489Sambrisko devclass = devclass_find("mfi"); 3183177489Sambrisko sc = devclass_get_softc(devclass, adapter); 3184177489Sambrisko } 3185164281Sambrisko mtx_lock(&sc->mfi_io_lock); 3186164281Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 3187164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3188164281Sambrisko return (EBUSY); 3189164281Sambrisko } 3190164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3191171821Sjhb locked = 0; 3192164281Sambrisko 3193164281Sambrisko /* 3194164281Sambrisko * save off original context since copying from user 3195164281Sambrisko * will clobber some data 3196164281Sambrisko */ 3197164281Sambrisko context = cm->cm_frame->header.context; 3198233711Sambrisko cm->cm_frame->header.context = cm->cm_index; 3199164281Sambrisko 3200165225Sambrisko bcopy(ioc->mfi_frame.raw, cm->cm_frame, 3201233711Sambrisko 2 * MEGAMFI_FRAME_SIZE); 3202184897Sambrisko cm->cm_total_frame_size = (sizeof(union mfi_sgl) 3203184897Sambrisko * ioc->mfi_sge_count) + ioc->mfi_sgl_off; 3204233711Sambrisko cm->cm_frame->header.scsi_status = 0; 3205233711Sambrisko cm->cm_frame->header.pad0 = 0; 3206175897Sambrisko if (ioc->mfi_sge_count) { 3207175897Sambrisko cm->cm_sg = 3208175897Sambrisko (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off]; 3209175897Sambrisko } 3210233711Sambrisko sgl = cm->cm_sg; 3211175897Sambrisko cm->cm_flags = 0; 3212175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN) 3213175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN; 3214175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT) 3215175897Sambrisko cm->cm_flags |= MFI_CMD_DATAOUT; 3216175897Sambrisko /* Legacy app shim */ 3217175897Sambrisko if (cm->cm_flags == 0) 3218175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT; 3219164281Sambrisko cm->cm_len = cm->cm_frame->header.data_len; 3220225869Smav if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3221233711Sambrisko#ifdef COMPAT_FREEBSD32 3222225869Smav if (cmd == MFI_CMD) { 3223225869Smav#endif 3224225869Smav /* Native */ 3225225869Smav cm->cm_stp_len = ioc->mfi_sgl[0].iov_len; 3226233711Sambrisko#ifdef COMPAT_FREEBSD32 3227225869Smav } else { 3228225869Smav /* 32bit on 64bit */ 3229225869Smav ioc32 = (struct mfi_ioc_packet32 *)ioc; 3230225869Smav cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len; 3231225869Smav } 3232225869Smav#endif 3233225869Smav cm->cm_len += cm->cm_stp_len; 3234225869Smav } 3235184897Sambrisko if (cm->cm_len && 3236184897Sambrisko (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) { 3237175897Sambrisko cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF, 3238175897Sambrisko M_WAITOK | M_ZERO); 3239175897Sambrisko if (cm->cm_data == NULL) { 3240175897Sambrisko device_printf(sc->mfi_dev, "Malloc failed\n"); 3241175897Sambrisko goto out; 3242175897Sambrisko } 3243175897Sambrisko } else { 3244175897Sambrisko cm->cm_data = 0; 3245165225Sambrisko } 3246164281Sambrisko 3247164281Sambrisko /* restore header context */ 3248164281Sambrisko cm->cm_frame->header.context = context; 3249164281Sambrisko 3250233711Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3251233711Sambrisko res = mfi_stp_cmd(sc, cm, arg); 3252233711Sambrisko if (res != 0) 3253233711Sambrisko goto out; 3254233711Sambrisko } else { 3255233711Sambrisko temp = data; 3256233711Sambrisko if ((cm->cm_flags & MFI_CMD_DATAOUT) || 3257233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_STP)) { 3258233711Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 3259233711Sambrisko#ifdef COMPAT_FREEBSD32 3260233711Sambrisko if (cmd == MFI_CMD) { 3261225869Smav#endif 3262233711Sambrisko /* Native */ 3263233711Sambrisko addr = ioc->mfi_sgl[i].iov_base; 3264233711Sambrisko len = ioc->mfi_sgl[i].iov_len; 3265233711Sambrisko#ifdef COMPAT_FREEBSD32 3266233711Sambrisko } else { 3267233711Sambrisko /* 32bit on 64bit */ 3268233711Sambrisko ioc32 = (struct mfi_ioc_packet32 *)ioc; 3269233711Sambrisko addr = PTRIN(ioc32->mfi_sgl[i].iov_base); 3270233711Sambrisko len = ioc32->mfi_sgl[i].iov_len; 3271233711Sambrisko } 3272179392Sambrisko#endif 3273233711Sambrisko error = copyin(addr, temp, len); 3274233711Sambrisko if (error != 0) { 3275233711Sambrisko device_printf(sc->mfi_dev, 3276233711Sambrisko "Copy in failed\n"); 3277233711Sambrisko goto out; 3278233711Sambrisko } 3279233711Sambrisko temp = &temp[len]; 3280175897Sambrisko } 3281164281Sambrisko } 3282164281Sambrisko } 3283164281Sambrisko 3284171821Sjhb if (cm->cm_frame->header.cmd == MFI_CMD_DCMD) 3285233711Sambrisko locked = mfi_config_lock(sc, 3286233711Sambrisko cm->cm_frame->dcmd.opcode); 3287171821Sjhb 3288184933Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { 3289233711Sambrisko cm->cm_frame->pass.sense_addr_lo = 3290233711Sambrisko (uint32_t)cm->cm_sense_busaddr; 3291233711Sambrisko cm->cm_frame->pass.sense_addr_hi = 3292233711Sambrisko (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 3293184933Sambrisko } 3294164281Sambrisko mtx_lock(&sc->mfi_io_lock); 3295233711Sambrisko skip_pre_post = mfi_check_for_sscd (sc, cm); 3296233711Sambrisko if (!skip_pre_post) { 3297233711Sambrisko error = mfi_check_command_pre(sc, cm); 3298233711Sambrisko if (error) { 3299233711Sambrisko mtx_unlock(&sc->mfi_io_lock); 3300233711Sambrisko goto out; 3301233711Sambrisko } 3302171821Sjhb } 3303170284Sambrisko if ((error = mfi_wait_command(sc, cm)) != 0) { 3304164281Sambrisko device_printf(sc->mfi_dev, 3305165225Sambrisko "Controller polled failed\n"); 3306164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3307164281Sambrisko goto out; 3308164281Sambrisko } 3309233711Sambrisko if (!skip_pre_post) { 3310233711Sambrisko mfi_check_command_post(sc, cm); 3311233711Sambrisko } 3312164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3313164281Sambrisko 3314233711Sambrisko if (cm->cm_frame->header.cmd != MFI_CMD_STP) { 3315233711Sambrisko temp = data; 3316233711Sambrisko if ((cm->cm_flags & MFI_CMD_DATAIN) || 3317233711Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_STP)) { 3318233711Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 3319233711Sambrisko#ifdef COMPAT_FREEBSD32 3320233711Sambrisko if (cmd == MFI_CMD) { 3321225869Smav#endif 3322233711Sambrisko /* Native */ 3323233711Sambrisko addr = ioc->mfi_sgl[i].iov_base; 3324233711Sambrisko len = ioc->mfi_sgl[i].iov_len; 3325233711Sambrisko#ifdef COMPAT_FREEBSD32 3326233711Sambrisko } else { 3327233711Sambrisko /* 32bit on 64bit */ 3328233711Sambrisko ioc32 = (struct mfi_ioc_packet32 *)ioc; 3329233711Sambrisko addr = PTRIN(ioc32->mfi_sgl[i].iov_base); 3330233711Sambrisko len = ioc32->mfi_sgl[i].iov_len; 3331233711Sambrisko } 3332179392Sambrisko#endif 3333233711Sambrisko error = copyout(temp, addr, len); 3334233711Sambrisko if (error != 0) { 3335233711Sambrisko device_printf(sc->mfi_dev, 3336233711Sambrisko "Copy out failed\n"); 3337233711Sambrisko goto out; 3338233711Sambrisko } 3339233711Sambrisko temp = &temp[len]; 3340175897Sambrisko } 3341164281Sambrisko } 3342164281Sambrisko } 3343164281Sambrisko 3344165225Sambrisko if (ioc->mfi_sense_len) { 3345184897Sambrisko /* get user-space sense ptr then copy out sense */ 3346225428Sbz bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off], 3347184897Sambrisko &sense_ptr.sense_ptr_data[0], 3348184897Sambrisko sizeof(sense_ptr.sense_ptr_data)); 3349233711Sambrisko#ifdef COMPAT_FREEBSD32 3350184974Sambrisko if (cmd != MFI_CMD) { 3351184974Sambrisko /* 3352184974Sambrisko * not 64bit native so zero out any address 3353184974Sambrisko * over 32bit */ 3354184975Sambrisko sense_ptr.addr.high = 0; 3355184974Sambrisko } 3356184974Sambrisko#endif 3357184897Sambrisko error = copyout(cm->cm_sense, sense_ptr.user_space, 3358165225Sambrisko ioc->mfi_sense_len); 3359164281Sambrisko if (error != 0) { 3360164281Sambrisko device_printf(sc->mfi_dev, 3361165225Sambrisko "Copy out failed\n"); 3362164281Sambrisko goto out; 3363164281Sambrisko } 3364164281Sambrisko } 3365164281Sambrisko 3366165225Sambrisko ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status; 3367164281Sambriskoout: 3368171821Sjhb mfi_config_unlock(sc, locked); 3369164281Sambrisko if (data) 3370164281Sambrisko free(data, M_MFIBUF); 3371233711Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3372233711Sambrisko for (i = 0; i < 2; i++) { 3373233711Sambrisko if (sc->kbuff_arr[i]) { 3374233711Sambrisko if (sc->mfi_kbuff_arr_busaddr != 0) 3375233711Sambrisko bus_dmamap_unload( 3376233711Sambrisko sc->mfi_kbuff_arr_dmat[i], 3377233711Sambrisko sc->mfi_kbuff_arr_dmamap[i] 3378233711Sambrisko ); 3379233711Sambrisko if (sc->kbuff_arr[i] != NULL) 3380233711Sambrisko bus_dmamem_free( 3381233711Sambrisko sc->mfi_kbuff_arr_dmat[i], 3382233711Sambrisko sc->kbuff_arr[i], 3383233711Sambrisko sc->mfi_kbuff_arr_dmamap[i] 3384233711Sambrisko ); 3385233711Sambrisko if (sc->mfi_kbuff_arr_dmat[i] != NULL) 3386233711Sambrisko bus_dma_tag_destroy( 3387233711Sambrisko sc->mfi_kbuff_arr_dmat[i]); 3388233711Sambrisko } 3389233711Sambrisko } 3390233711Sambrisko } 3391164281Sambrisko if (cm) { 3392164281Sambrisko mtx_lock(&sc->mfi_io_lock); 3393164281Sambrisko mfi_release_command(cm); 3394164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3395164281Sambrisko } 3396164281Sambrisko 3397164281Sambrisko break; 3398177489Sambrisko } 3399164281Sambrisko case MFI_SET_AEN: 3400164281Sambrisko aen = (struct mfi_ioc_aen *)arg; 3401247369Ssmh mtx_lock(&sc->mfi_io_lock); 3402164281Sambrisko error = mfi_aen_register(sc, aen->aen_seq_num, 3403164281Sambrisko aen->aen_class_locale); 3404247369Ssmh mtx_unlock(&sc->mfi_io_lock); 3405164281Sambrisko 3406164281Sambrisko break; 3407164281Sambrisko case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */ 3408158737Sambrisko { 3409158737Sambrisko devclass_t devclass; 3410158737Sambrisko struct mfi_linux_ioc_packet l_ioc; 3411158737Sambrisko int adapter; 3412158737Sambrisko 3413158737Sambrisko devclass = devclass_find("mfi"); 3414158737Sambrisko if (devclass == NULL) 3415158737Sambrisko return (ENOENT); 3416158737Sambrisko 3417158737Sambrisko error = copyin(arg, &l_ioc, sizeof(l_ioc)); 3418158737Sambrisko if (error) 3419158737Sambrisko return (error); 3420158737Sambrisko adapter = l_ioc.lioc_adapter_no; 3421158737Sambrisko sc = devclass_get_softc(devclass, adapter); 3422158737Sambrisko if (sc == NULL) 3423158737Sambrisko return (ENOENT); 3424158737Sambrisko return (mfi_linux_ioctl_int(sc->mfi_cdev, 3425158737Sambrisko cmd, arg, flag, td)); 3426158737Sambrisko break; 3427158737Sambrisko } 3428164281Sambrisko case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */ 3429158737Sambrisko { 3430158737Sambrisko devclass_t devclass; 3431158737Sambrisko struct mfi_linux_ioc_aen l_aen; 3432158737Sambrisko int adapter; 3433158737Sambrisko 3434158737Sambrisko devclass = devclass_find("mfi"); 3435158737Sambrisko if (devclass == NULL) 3436158737Sambrisko return (ENOENT); 3437158737Sambrisko 3438158737Sambrisko error = copyin(arg, &l_aen, sizeof(l_aen)); 3439158737Sambrisko if (error) 3440158737Sambrisko return (error); 3441158737Sambrisko adapter = l_aen.laen_adapter_no; 3442158737Sambrisko sc = devclass_get_softc(devclass, adapter); 3443158737Sambrisko if (sc == NULL) 3444158737Sambrisko return (ENOENT); 3445158737Sambrisko return (mfi_linux_ioctl_int(sc->mfi_cdev, 3446158737Sambrisko cmd, arg, flag, td)); 3447158737Sambrisko break; 3448158737Sambrisko } 3449233711Sambrisko#ifdef COMPAT_FREEBSD32 3450178968Sscottl case MFIIO_PASSTHRU32: 3451238077Sjhb if (!SV_CURPROC_FLAG(SV_ILP32)) { 3452238077Sjhb error = ENOTTY; 3453238077Sjhb break; 3454238077Sjhb } 3455178968Sscottl iop_swab.ioc_frame = iop32->ioc_frame; 3456178968Sscottl iop_swab.buf_size = iop32->buf_size; 3457178968Sscottl iop_swab.buf = PTRIN(iop32->buf); 3458178968Sscottl iop = &iop_swab; 3459178968Sscottl /* FALLTHROUGH */ 3460178968Sscottl#endif 3461178968Sscottl case MFIIO_PASSTHRU: 3462178968Sscottl error = mfi_user_command(sc, iop); 3463233711Sambrisko#ifdef COMPAT_FREEBSD32 3464178968Sscottl if (cmd == MFIIO_PASSTHRU32) 3465178968Sscottl iop32->ioc_frame = iop_swab.ioc_frame; 3466178968Sscottl#endif 3467178968Sscottl break; 3468157114Sscottl default: 3469163398Sscottl device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); 3470238077Sjhb error = ENOTTY; 3471157114Sscottl break; 3472157114Sscottl } 3473157114Sscottl 3474157114Sscottl return (error); 3475157114Sscottl} 3476158737Sambrisko 3477158737Sambriskostatic int 3478192450Simpmfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 3479158737Sambrisko{ 3480158737Sambrisko struct mfi_softc *sc; 3481158737Sambrisko struct mfi_linux_ioc_packet l_ioc; 3482158737Sambrisko struct mfi_linux_ioc_aen l_aen; 3483158737Sambrisko struct mfi_command *cm = NULL; 3484158737Sambrisko struct mfi_aen *mfi_aen_entry; 3485184897Sambrisko union mfi_sense_ptr sense_ptr; 3486233711Sambrisko uint32_t context = 0; 3487158737Sambrisko uint8_t *data = NULL, *temp; 3488158737Sambrisko int i; 3489171821Sjhb int error, locked; 3490158737Sambrisko 3491158737Sambrisko sc = dev->si_drv1; 3492158737Sambrisko error = 0; 3493158737Sambrisko switch (cmd) { 3494164281Sambrisko case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */ 3495158737Sambrisko error = copyin(arg, &l_ioc, sizeof(l_ioc)); 3496158737Sambrisko if (error != 0) 3497158737Sambrisko return (error); 3498158737Sambrisko 3499158737Sambrisko if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) { 3500158737Sambrisko return (EINVAL); 3501158737Sambrisko } 3502158737Sambrisko 3503158737Sambrisko mtx_lock(&sc->mfi_io_lock); 3504158737Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 3505158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3506158737Sambrisko return (EBUSY); 3507158737Sambrisko } 3508158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3509171821Sjhb locked = 0; 3510158737Sambrisko 3511158737Sambrisko /* 3512158737Sambrisko * save off original context since copying from user 3513158737Sambrisko * will clobber some data 3514158737Sambrisko */ 3515158737Sambrisko context = cm->cm_frame->header.context; 3516158737Sambrisko 3517158737Sambrisko bcopy(l_ioc.lioc_frame.raw, cm->cm_frame, 3518175897Sambrisko 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */ 3519184897Sambrisko cm->cm_total_frame_size = (sizeof(union mfi_sgl) 3520184897Sambrisko * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off; 3521233711Sambrisko cm->cm_frame->header.scsi_status = 0; 3522233711Sambrisko cm->cm_frame->header.pad0 = 0; 3523175897Sambrisko if (l_ioc.lioc_sge_count) 3524175897Sambrisko cm->cm_sg = 3525175897Sambrisko (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off]; 3526175897Sambrisko cm->cm_flags = 0; 3527175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN) 3528175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN; 3529175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT) 3530175897Sambrisko cm->cm_flags |= MFI_CMD_DATAOUT; 3531158737Sambrisko cm->cm_len = cm->cm_frame->header.data_len; 3532184897Sambrisko if (cm->cm_len && 3533184897Sambrisko (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) { 3534175897Sambrisko cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF, 3535175897Sambrisko M_WAITOK | M_ZERO); 3536175897Sambrisko if (cm->cm_data == NULL) { 3537175897Sambrisko device_printf(sc->mfi_dev, "Malloc failed\n"); 3538175897Sambrisko goto out; 3539175897Sambrisko } 3540175897Sambrisko } else { 3541175897Sambrisko cm->cm_data = 0; 3542175897Sambrisko } 3543158737Sambrisko 3544158737Sambrisko /* restore header context */ 3545158737Sambrisko cm->cm_frame->header.context = context; 3546158737Sambrisko 3547158737Sambrisko temp = data; 3548175897Sambrisko if (cm->cm_flags & MFI_CMD_DATAOUT) { 3549175897Sambrisko for (i = 0; i < l_ioc.lioc_sge_count; i++) { 3550178968Sscottl error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base), 3551175897Sambrisko temp, 3552175897Sambrisko l_ioc.lioc_sgl[i].iov_len); 3553175897Sambrisko if (error != 0) { 3554175897Sambrisko device_printf(sc->mfi_dev, 3555175897Sambrisko "Copy in failed\n"); 3556175897Sambrisko goto out; 3557175897Sambrisko } 3558175897Sambrisko temp = &temp[l_ioc.lioc_sgl[i].iov_len]; 3559158737Sambrisko } 3560158737Sambrisko } 3561158737Sambrisko 3562171821Sjhb if (cm->cm_frame->header.cmd == MFI_CMD_DCMD) 3563171821Sjhb locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode); 3564171821Sjhb 3565184933Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { 3566233711Sambrisko cm->cm_frame->pass.sense_addr_lo = 3567233711Sambrisko (uint32_t)cm->cm_sense_busaddr; 3568233711Sambrisko cm->cm_frame->pass.sense_addr_hi = 3569233711Sambrisko (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 3570184933Sambrisko } 3571184933Sambrisko 3572163398Sscottl mtx_lock(&sc->mfi_io_lock); 3573171821Sjhb error = mfi_check_command_pre(sc, cm); 3574171821Sjhb if (error) { 3575171821Sjhb mtx_unlock(&sc->mfi_io_lock); 3576171821Sjhb goto out; 3577171821Sjhb } 3578171821Sjhb 3579170284Sambrisko if ((error = mfi_wait_command(sc, cm)) != 0) { 3580158737Sambrisko device_printf(sc->mfi_dev, 3581165225Sambrisko "Controller polled failed\n"); 3582163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3583158737Sambrisko goto out; 3584158737Sambrisko } 3585158737Sambrisko 3586171821Sjhb mfi_check_command_post(sc, cm); 3587163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3588158737Sambrisko 3589158737Sambrisko temp = data; 3590175897Sambrisko if (cm->cm_flags & MFI_CMD_DATAIN) { 3591175897Sambrisko for (i = 0; i < l_ioc.lioc_sge_count; i++) { 3592175897Sambrisko error = copyout(temp, 3593178968Sscottl PTRIN(l_ioc.lioc_sgl[i].iov_base), 3594175897Sambrisko l_ioc.lioc_sgl[i].iov_len); 3595175897Sambrisko if (error != 0) { 3596175897Sambrisko device_printf(sc->mfi_dev, 3597175897Sambrisko "Copy out failed\n"); 3598175897Sambrisko goto out; 3599175897Sambrisko } 3600175897Sambrisko temp = &temp[l_ioc.lioc_sgl[i].iov_len]; 3601158737Sambrisko } 3602158737Sambrisko } 3603158737Sambrisko 3604158737Sambrisko if (l_ioc.lioc_sense_len) { 3605184897Sambrisko /* get user-space sense ptr then copy out sense */ 3606184897Sambrisko bcopy(&((struct mfi_linux_ioc_packet*)arg) 3607184897Sambrisko ->lioc_frame.raw[l_ioc.lioc_sense_off], 3608184897Sambrisko &sense_ptr.sense_ptr_data[0], 3609184897Sambrisko sizeof(sense_ptr.sense_ptr_data)); 3610184974Sambrisko#ifdef __amd64__ 3611184974Sambrisko /* 3612184974Sambrisko * only 32bit Linux support so zero out any 3613184974Sambrisko * address over 32bit 3614184974Sambrisko */ 3615184975Sambrisko sense_ptr.addr.high = 0; 3616184974Sambrisko#endif 3617184897Sambrisko error = copyout(cm->cm_sense, sense_ptr.user_space, 3618158737Sambrisko l_ioc.lioc_sense_len); 3619158737Sambrisko if (error != 0) { 3620158737Sambrisko device_printf(sc->mfi_dev, 3621165225Sambrisko "Copy out failed\n"); 3622158737Sambrisko goto out; 3623158737Sambrisko } 3624158737Sambrisko } 3625158737Sambrisko 3626158737Sambrisko error = copyout(&cm->cm_frame->header.cmd_status, 3627158737Sambrisko &((struct mfi_linux_ioc_packet*)arg) 3628158737Sambrisko ->lioc_frame.hdr.cmd_status, 3629158737Sambrisko 1); 3630158737Sambrisko if (error != 0) { 3631158737Sambrisko device_printf(sc->mfi_dev, 3632165225Sambrisko "Copy out failed\n"); 3633158737Sambrisko goto out; 3634158737Sambrisko } 3635158737Sambrisko 3636158737Sambriskoout: 3637171821Sjhb mfi_config_unlock(sc, locked); 3638158737Sambrisko if (data) 3639158737Sambrisko free(data, M_MFIBUF); 3640158737Sambrisko if (cm) { 3641158737Sambrisko mtx_lock(&sc->mfi_io_lock); 3642158737Sambrisko mfi_release_command(cm); 3643158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3644158737Sambrisko } 3645158737Sambrisko 3646158737Sambrisko return (error); 3647164281Sambrisko case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */ 3648158737Sambrisko error = copyin(arg, &l_aen, sizeof(l_aen)); 3649158737Sambrisko if (error != 0) 3650158737Sambrisko return (error); 3651158737Sambrisko printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid); 3652158737Sambrisko mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF, 3653158737Sambrisko M_WAITOK); 3654163398Sscottl mtx_lock(&sc->mfi_io_lock); 3655158737Sambrisko if (mfi_aen_entry != NULL) { 3656158737Sambrisko mfi_aen_entry->p = curproc; 3657158737Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry, 3658158737Sambrisko aen_link); 3659158737Sambrisko } 3660158737Sambrisko error = mfi_aen_register(sc, l_aen.laen_seq_num, 3661158737Sambrisko l_aen.laen_class_locale); 3662158737Sambrisko 3663158737Sambrisko if (error != 0) { 3664158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 3665158737Sambrisko aen_link); 3666158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 3667158737Sambrisko } 3668163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3669158737Sambrisko 3670158737Sambrisko return (error); 3671158737Sambrisko default: 3672158737Sambrisko device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); 3673158737Sambrisko error = ENOENT; 3674158737Sambrisko break; 3675158737Sambrisko } 3676158737Sambrisko 3677158737Sambrisko return (error); 3678158737Sambrisko} 3679158737Sambrisko 3680158737Sambriskostatic int 3681158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td) 3682158737Sambrisko{ 3683158737Sambrisko struct mfi_softc *sc; 3684158737Sambrisko int revents = 0; 3685158737Sambrisko 3686158737Sambrisko sc = dev->si_drv1; 3687158737Sambrisko 3688158737Sambrisko if (poll_events & (POLLIN | POLLRDNORM)) { 3689163398Sscottl if (sc->mfi_aen_triggered != 0) { 3690158737Sambrisko revents |= poll_events & (POLLIN | POLLRDNORM); 3691163398Sscottl sc->mfi_aen_triggered = 0; 3692163398Sscottl } 3693158737Sambrisko if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) { 3694158737Sambrisko revents |= POLLERR; 3695158737Sambrisko } 3696158737Sambrisko } 3697158737Sambrisko 3698158737Sambrisko if (revents == 0) { 3699158737Sambrisko if (poll_events & (POLLIN | POLLRDNORM)) { 3700158737Sambrisko sc->mfi_poll_waiting = 1; 3701158737Sambrisko selrecord(td, &sc->mfi_select); 3702158737Sambrisko } 3703158737Sambrisko } 3704158737Sambrisko 3705158737Sambrisko return revents; 3706158737Sambrisko} 3707162619Sscottl 3708162619Sscottlstatic void 3709163398Sscottlmfi_dump_all(void) 3710163398Sscottl{ 3711163398Sscottl struct mfi_softc *sc; 3712163398Sscottl struct mfi_command *cm; 3713163398Sscottl devclass_t dc; 3714163398Sscottl time_t deadline; 3715163398Sscottl int timedout; 3716163398Sscottl int i; 3717163398Sscottl 3718163398Sscottl dc = devclass_find("mfi"); 3719163398Sscottl if (dc == NULL) { 3720163398Sscottl printf("No mfi dev class\n"); 3721163398Sscottl return; 3722163398Sscottl } 3723163398Sscottl 3724163398Sscottl for (i = 0; ; i++) { 3725163398Sscottl sc = devclass_get_softc(dc, i); 3726163398Sscottl if (sc == NULL) 3727163398Sscottl break; 3728163398Sscottl device_printf(sc->mfi_dev, "Dumping\n\n"); 3729163398Sscottl timedout = 0; 3730247426Ssmh deadline = time_uptime - mfi_cmd_timeout; 3731163398Sscottl mtx_lock(&sc->mfi_io_lock); 3732163398Sscottl TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) { 3733247369Ssmh if (cm->cm_timestamp <= deadline) { 3734163398Sscottl device_printf(sc->mfi_dev, 3735233711Sambrisko "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 3736233711Sambrisko cm, (int)(time_uptime - cm->cm_timestamp)); 3737163398Sscottl MFI_PRINT_CMD(cm); 3738163398Sscottl timedout++; 3739163398Sscottl } 3740163398Sscottl } 3741163398Sscottl 3742163398Sscottl#if 0 3743163398Sscottl if (timedout) 3744247369Ssmh MFI_DUMP_CMDS(sc); 3745163398Sscottl#endif 3746163398Sscottl 3747163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3748163398Sscottl } 3749163398Sscottl 3750163398Sscottl return; 3751163398Sscottl} 3752163398Sscottl 3753163398Sscottlstatic void 3754162619Sscottlmfi_timeout(void *data) 3755162619Sscottl{ 3756162619Sscottl struct mfi_softc *sc = (struct mfi_softc *)data; 3757247369Ssmh struct mfi_command *cm, *tmp; 3758162619Sscottl time_t deadline; 3759162619Sscottl int timedout = 0; 3760162619Sscottl 3761247426Ssmh deadline = time_uptime - mfi_cmd_timeout; 3762233711Sambrisko if (sc->adpreset == 0) { 3763233711Sambrisko if (!mfi_tbolt_reset(sc)) { 3764247426Ssmh callout_reset(&sc->mfi_watchdog_callout, 3765247426Ssmh mfi_cmd_timeout * hz, mfi_timeout, sc); 3766233711Sambrisko return; 3767233711Sambrisko } 3768233711Sambrisko } 3769162619Sscottl mtx_lock(&sc->mfi_io_lock); 3770247369Ssmh TAILQ_FOREACH_SAFE(cm, &sc->mfi_busy, cm_link, tmp) { 3771235014Sambrisko if (sc->mfi_aen_cm == cm || sc->mfi_map_sync_cm == cm) 3772162688Sscottl continue; 3773247369Ssmh if (cm->cm_timestamp <= deadline) { 3774233711Sambrisko if (sc->adpreset != 0 && sc->issuepend_done == 0) { 3775233711Sambrisko cm->cm_timestamp = time_uptime; 3776233711Sambrisko } else { 3777233711Sambrisko device_printf(sc->mfi_dev, 3778233711Sambrisko "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 3779233711Sambrisko cm, (int)(time_uptime - cm->cm_timestamp) 3780233711Sambrisko ); 3781233711Sambrisko MFI_PRINT_CMD(cm); 3782233711Sambrisko MFI_VALIDATE_CMD(sc, cm); 3783247369Ssmh /* 3784252471Ssmh * While commands can get stuck forever we do 3785252471Ssmh * not fail them as there is no way to tell if 3786252471Ssmh * the controller has actually processed them 3787252471Ssmh * or not. 3788252471Ssmh * 3789252471Ssmh * In addition its very likely that force 3790252471Ssmh * failing a command here would cause a panic 3791252471Ssmh * e.g. in UFS. 3792247369Ssmh */ 3793233711Sambrisko timedout++; 3794233711Sambrisko } 3795162619Sscottl } 3796162619Sscottl } 3797162619Sscottl 3798162619Sscottl#if 0 3799162619Sscottl if (timedout) 3800247369Ssmh MFI_DUMP_CMDS(sc); 3801162619Sscottl#endif 3802162619Sscottl 3803162619Sscottl mtx_unlock(&sc->mfi_io_lock); 3804162619Sscottl 3805247426Ssmh callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz, 3806162619Sscottl mfi_timeout, sc); 3807162619Sscottl 3808163398Sscottl if (0) 3809163398Sscottl mfi_dump_all(); 3810162619Sscottl return; 3811162619Sscottl} 3812