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$"); 55157114Sscottl 56234429Sambrisko#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> 76239866Sjhb#include <sys/sysent.h> 77234429Sambrisko#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> 85234429Sambrisko#include <sys/interrupt.h> 86234429Sambrisko#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); 98234429Sambriskostatic void mfi_syspdprobe(struct mfi_softc *sc); 99234429Sambriskostatic 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 *); 104234429Sambriskostatic int mfi_add_sys_pd(struct mfi_softc *sc, int); 105234429Sambriskostatic 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 *); 108234429Sambriskostatic struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*); 109234429Sambriskostatic struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*); 110157114Sscottlstatic int mfi_send_frame(struct mfi_softc *, struct mfi_command *); 111250496Ssmhstatic int mfi_std_send_frame(struct mfi_softc *, struct mfi_command *); 112243824Sdelphijstatic 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 *); 117234429Sambriskostatic void mfi_enable_intr_xscale(struct mfi_softc *sc); 118234429Sambriskostatic void mfi_enable_intr_ppc(struct mfi_softc *sc); 119234429Sambriskostatic int32_t mfi_read_fw_status_xscale(struct mfi_softc *sc); 120234429Sambriskostatic int32_t mfi_read_fw_status_ppc(struct mfi_softc *sc); 121234429Sambriskostatic int mfi_check_clear_intr_xscale(struct mfi_softc *sc); 122234429Sambriskostatic int mfi_check_clear_intr_ppc(struct mfi_softc *sc); 123234429Sambriskostatic void mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, 124234429Sambrisko uint32_t frame_cnt); 125234429Sambriskostatic void mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, 126234429Sambrisko uint32_t frame_cnt); 127234429Sambriskostatic int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode); 128234429Sambriskostatic void mfi_config_unlock(struct mfi_softc *sc, int locked); 129234429Sambriskostatic int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm); 130234429Sambriskostatic void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm); 131234429Sambriskostatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm); 132157114Sscottl 133162118SambriskoSYSCTL_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); 136250496SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RWTUN, &mfi_event_locale, 137250496Ssmh 0, "event message locale"); 138162473Sambrisko 139165852Sscottlstatic int mfi_event_class = MFI_EVT_CLASS_INFO; 140162473SambriskoTUNABLE_INT("hw.mfi.event_class", &mfi_event_class); 141250496SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RWTUN, &mfi_event_class, 142250496Ssmh 0, "event message class"); 143162118Sambrisko 144178968Sscottlstatic int mfi_max_cmds = 128; 145178968SscottlTUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds); 146250496SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RDTUN, &mfi_max_cmds, 147250496Ssmh 0, "Max commands limit (-1 = controller limit)"); 148178968Sscottl 149234429Sambriskostatic int mfi_detect_jbod_change = 1; 150234429SambriskoTUNABLE_INT("hw.mfi.detect_jbod_change", &mfi_detect_jbod_change); 151250496SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RWTUN, 152234429Sambrisko &mfi_detect_jbod_change, 0, "Detect a change to a JBOD"); 153234429Sambrisko 154250496Ssmhint mfi_polled_cmd_timeout = MFI_POLL_TIMEOUT_SECS; 155250496SsmhTUNABLE_INT("hw.mfi.polled_cmd_timeout", &mfi_polled_cmd_timeout); 156250496SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, polled_cmd_timeout, CTLFLAG_RWTUN, 157250496Ssmh &mfi_polled_cmd_timeout, 0, 158250496Ssmh "Polled command timeout - used for firmware flash etc (in seconds)"); 159250496Ssmh 160251406Ssmhstatic int mfi_cmd_timeout = MFI_CMD_TIMEOUT; 161251406SsmhTUNABLE_INT("hw.mfi.cmd_timeout", &mfi_cmd_timeout); 162251406SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, cmd_timeout, CTLFLAG_RWTUN, &mfi_cmd_timeout, 163251406Ssmh 0, "Command timeout (in seconds)"); 164251406Ssmh 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 184234429Sambriskostruct 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) { 196234429Sambrisko MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF); 197184897Sambrisko MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM); 198234429Sambrisko } 199234429Sambrisko else if (sc->mfi_flags & MFI_FLAGS_GEN2) { 200234429Sambrisko MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF); 201184897Sambrisko MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM); 202184897Sambrisko } 203234429Sambrisko else if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 204234429Sambrisko MFI_WRITE4(sc, MFI_OMSK, ~0x00000001); 205234429Sambrisko } 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 } 243234429Sambrisko } 244234429Sambrisko else if (sc->mfi_flags & MFI_FLAGS_GEN2) { 245184897Sambrisko if (!(status & MFI_GEN2_RM)) { 246184897Sambrisko return 1; 247184897Sambrisko } 248184897Sambrisko } 249234429Sambrisko else if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 250234429Sambrisko if (!(status & MFI_SKINNY_RM)) { 251234429Sambrisko return 1; 252234429Sambrisko } 253234429Sambrisko } 254234429Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) 255234429Sambrisko MFI_WRITE4(sc, MFI_OSTS, status); 256234429Sambrisko else 257234429Sambrisko MFI_WRITE4(sc, MFI_ODCR0, status); 258171980Sscottl return 0; 259182085Simp} 260171980Sscottl 261184897Sambriskostatic void 262234429Sambriskomfi_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 268234429Sambriskomfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt) 269171980Sscottl{ 270234429Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 271234429Sambrisko MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt <<1)|1 ); 272234429Sambrisko MFI_WRITE4(sc, MFI_IQPH, 0x00000000); 273234429Sambrisko } else { 274234429Sambrisko MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt <<1)|1 ); 275234429Sambrisko } 276171980Sscottl} 277171980Sscottl 278234429Sambriskoint 279157114Sscottlmfi_transition_firmware(struct mfi_softc *sc) 280157114Sscottl{ 281194851Sscottl uint32_t fw_state, cur_state; 282157114Sscottl int max_wait, i; 283234429Sambrisko uint32_t cur_abs_reg_val = 0; 284234429Sambrisko uint32_t prev_abs_reg_val = 0; 285157114Sscottl 286234429Sambrisko cur_abs_reg_val = sc->mfi_read_fw_status(sc); 287234429Sambrisko 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: 298234429Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 299234429Sambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE); 300234429Sambrisko else 301234429Sambrisko MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE); 302234429Sambrisko max_wait = MFI_RESET_WAIT_TIME; 303157114Sscottl break; 304157114Sscottl case MFI_FWSTATE_OPERATIONAL: 305234429Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 306234429Sambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, 7); 307234429Sambrisko else 308234429Sambrisko MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY); 309234429Sambrisko max_wait = MFI_RESET_WAIT_TIME; 310157114Sscottl break; 311157114Sscottl case MFI_FWSTATE_UNDEFINED: 312157114Sscottl case MFI_FWSTATE_BB_INIT: 313234429Sambrisko max_wait = MFI_RESET_WAIT_TIME; 314157114Sscottl break; 315234429Sambrisko case MFI_FWSTATE_FW_INIT_2: 316234429Sambrisko max_wait = MFI_RESET_WAIT_TIME; 317234429Sambrisko break; 318157114Sscottl case MFI_FWSTATE_FW_INIT: 319157114Sscottl case MFI_FWSTATE_FLUSH_CACHE: 320234429Sambrisko max_wait = MFI_RESET_WAIT_TIME; 321157114Sscottl break; 322234429Sambrisko case MFI_FWSTATE_DEVICE_SCAN: 323234429Sambrisko max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */ 324234429Sambrisko prev_abs_reg_val = cur_abs_reg_val; 325234429Sambrisko break; 326224041Sjhb case MFI_FWSTATE_BOOT_MESSAGE_PENDING: 327234429Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 328234429Sambrisko MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG); 329234429Sambrisko else 330234429Sambrisko MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG); 331234429Sambrisko max_wait = MFI_RESET_WAIT_TIME; 332224041Sjhb break; 333157114Sscottl default: 334234429Sambrisko 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++) { 339234429Sambrisko cur_abs_reg_val = sc->mfi_read_fw_status(sc); 340234429Sambrisko fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK; 341157114Sscottl if (fw_state == cur_state) 342157114Sscottl DELAY(100000); 343157114Sscottl else 344157114Sscottl break; 345157114Sscottl } 346234429Sambrisko if (fw_state == MFI_FWSTATE_DEVICE_SCAN) { 347234429Sambrisko /* Check the device scanning progress */ 348234429Sambrisko if (prev_abs_reg_val != cur_abs_reg_val) { 349234429Sambrisko continue; 350234429Sambrisko } 351234429Sambrisko } 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 362234429Sambriskomfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 363157114Sscottl{ 364234429Sambrisko bus_addr_t *addr; 365157114Sscottl 366157114Sscottl addr = arg; 367157114Sscottl *addr = segs[0].ds_addr; 368157114Sscottl} 369157114Sscottl 370234429Sambrisko 371157114Sscottlint 372157114Sscottlmfi_attach(struct mfi_softc *sc) 373157114Sscottl{ 374157114Sscottl uint32_t status; 375157114Sscottl int error, commsz, framessz, sensesz; 376250496Ssmh int frames, unit, max_fw_sge, max_fw_cmds; 377234429Sambrisko uint32_t tb_mem_size = 0; 378157114Sscottl 379234429Sambrisko if (sc == NULL) 380234429Sambrisko return EINVAL; 381186132Sambrisko 382234429Sambrisko device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n", 383234429Sambrisko MEGASAS_VERSION); 384234429Sambrisko 385157114Sscottl mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF); 386171821Sjhb sx_init(&sc->mfi_config_lock, "MFI config"); 387157114Sscottl TAILQ_INIT(&sc->mfi_ld_tqh); 388234429Sambrisko TAILQ_INIT(&sc->mfi_syspd_tqh); 389243824Sdelphij TAILQ_INIT(&sc->mfi_ld_pend_tqh); 390243824Sdelphij TAILQ_INIT(&sc->mfi_syspd_pend_tqh); 391234429Sambrisko TAILQ_INIT(&sc->mfi_evt_queue); 392234429Sambrisko TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc); 393235135Sambrisko TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc); 394158737Sambrisko TAILQ_INIT(&sc->mfi_aen_pids); 395169611Sscottl TAILQ_INIT(&sc->mfi_cam_ccbq); 396157114Sscottl 397157114Sscottl mfi_initq_free(sc); 398157114Sscottl mfi_initq_ready(sc); 399157114Sscottl mfi_initq_busy(sc); 400157114Sscottl mfi_initq_bio(sc); 401157114Sscottl 402234429Sambrisko sc->adpreset = 0; 403234429Sambrisko sc->last_seq_num = 0; 404234429Sambrisko sc->disableOnlineCtrlReset = 1; 405234429Sambrisko sc->issuepend_done = 1; 406234429Sambrisko sc->hw_crit_error = 0; 407234429Sambrisko 408171980Sscottl if (sc->mfi_flags & MFI_FLAGS_1064R) { 409171980Sscottl sc->mfi_enable_intr = mfi_enable_intr_xscale; 410171980Sscottl sc->mfi_read_fw_status = mfi_read_fw_status_xscale; 411171980Sscottl sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale; 412171980Sscottl sc->mfi_issue_cmd = mfi_issue_cmd_xscale; 413234429Sambrisko } else if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 414234429Sambrisko sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc; 415234429Sambrisko sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc; 416234429Sambrisko sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc; 417234429Sambrisko sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc; 418234429Sambrisko sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc; 419234429Sambrisko sc->mfi_adp_reset = mfi_tbolt_adp_reset; 420234429Sambrisko sc->mfi_tbolt = 1; 421234429Sambrisko TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh); 422234429Sambrisko } else { 423171980Sscottl sc->mfi_enable_intr = mfi_enable_intr_ppc; 424234429Sambrisko sc->mfi_read_fw_status = mfi_read_fw_status_ppc; 425171980Sscottl sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc; 426171980Sscottl sc->mfi_issue_cmd = mfi_issue_cmd_ppc; 427171980Sscottl } 428171980Sscottl 429171980Sscottl 430157114Sscottl /* Before we get too far, see if the firmware is working */ 431157114Sscottl if ((error = mfi_transition_firmware(sc)) != 0) { 432157114Sscottl device_printf(sc->mfi_dev, "Firmware not in READY state, " 433157114Sscottl "error %d\n", error); 434157114Sscottl return (ENXIO); 435157114Sscottl } 436157114Sscottl 437234429Sambrisko /* Start: LSIP200113393 */ 438234429Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 439234429Sambrisko 1, 0, /* algnmnt, boundary */ 440234429Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 441234429Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 442234429Sambrisko NULL, NULL, /* filter, filterarg */ 443234429Sambrisko MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsize */ 444234429Sambrisko 1, /* msegments */ 445234429Sambrisko MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsegsize */ 446234429Sambrisko 0, /* flags */ 447234429Sambrisko NULL, NULL, /* lockfunc, lockarg */ 448234429Sambrisko &sc->verbuf_h_dmat)) { 449234429Sambrisko device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n"); 450234429Sambrisko return (ENOMEM); 451234429Sambrisko } 452234429Sambrisko if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf, 453234429Sambrisko BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) { 454234429Sambrisko device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n"); 455234429Sambrisko return (ENOMEM); 456234429Sambrisko } 457234429Sambrisko bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t)); 458234429Sambrisko bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap, 459234429Sambrisko sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t), 460234429Sambrisko mfi_addr_cb, &sc->verbuf_h_busaddr, 0); 461234429Sambrisko /* End: LSIP200113393 */ 462234429Sambrisko 463157114Sscottl /* 464157114Sscottl * Get information needed for sizing the contiguous memory for the 465157114Sscottl * frame pool. Size down the sgl parameter since we know that 466157114Sscottl * we will never need more than what's required for MAXPHYS. 467157114Sscottl * It would be nice if these constants were available at runtime 468157114Sscottl * instead of compile time. 469157114Sscottl */ 470171980Sscottl status = sc->mfi_read_fw_status(sc); 471250496Ssmh max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK; 472250496Ssmh if (mfi_max_cmds > 0 && mfi_max_cmds < max_fw_cmds) { 473250496Ssmh device_printf(sc->mfi_dev, "FW MaxCmds = %d, limiting to %d\n", 474250496Ssmh max_fw_cmds, mfi_max_cmds); 475250496Ssmh sc->mfi_max_fw_cmds = mfi_max_cmds; 476250496Ssmh } else { 477250496Ssmh sc->mfi_max_fw_cmds = max_fw_cmds; 478250496Ssmh } 479162458Sscottl max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16; 480195534Sscottl sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1)); 481157114Sscottl 482234429Sambrisko /* ThunderBolt Support get the contiguous memory */ 483234429Sambrisko 484234429Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 485234429Sambrisko mfi_tbolt_init_globals(sc); 486250496Ssmh device_printf(sc->mfi_dev, "MaxCmd = %d, Drv MaxCmd = %d, " 487250496Ssmh "MaxSgl = %d, state = %#x\n", max_fw_cmds, 488234429Sambrisko sc->mfi_max_fw_cmds, sc->mfi_max_sge, status); 489234429Sambrisko tb_mem_size = mfi_tbolt_get_memory_requirement(sc); 490234429Sambrisko 491234429Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 492234429Sambrisko 1, 0, /* algnmnt, boundary */ 493234429Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 494234429Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 495234429Sambrisko NULL, NULL, /* filter, filterarg */ 496234429Sambrisko tb_mem_size, /* maxsize */ 497234429Sambrisko 1, /* msegments */ 498234429Sambrisko tb_mem_size, /* maxsegsize */ 499234429Sambrisko 0, /* flags */ 500234429Sambrisko NULL, NULL, /* lockfunc, lockarg */ 501234429Sambrisko &sc->mfi_tb_dmat)) { 502234429Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n"); 503234429Sambrisko return (ENOMEM); 504234429Sambrisko } 505234429Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool, 506234429Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) { 507234429Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 508234429Sambrisko return (ENOMEM); 509234429Sambrisko } 510234429Sambrisko bzero(sc->request_message_pool, tb_mem_size); 511234429Sambrisko bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap, 512234429Sambrisko sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0); 513234429Sambrisko 514234429Sambrisko /* For ThunderBolt memory init */ 515234429Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 516234429Sambrisko 0x100, 0, /* alignmnt, boundary */ 517234429Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 518234429Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 519234429Sambrisko NULL, NULL, /* filter, filterarg */ 520234429Sambrisko MFI_FRAME_SIZE, /* maxsize */ 521234429Sambrisko 1, /* msegments */ 522234429Sambrisko MFI_FRAME_SIZE, /* maxsegsize */ 523234429Sambrisko 0, /* flags */ 524234429Sambrisko NULL, NULL, /* lockfunc, lockarg */ 525234429Sambrisko &sc->mfi_tb_init_dmat)) { 526250496Ssmh device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n"); 527250496Ssmh return (ENOMEM); 528234429Sambrisko } 529234429Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init, 530234429Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) { 531234429Sambrisko device_printf(sc->mfi_dev, "Cannot allocate init memory\n"); 532234429Sambrisko return (ENOMEM); 533234429Sambrisko } 534234429Sambrisko bzero(sc->mfi_tb_init, MFI_FRAME_SIZE); 535234429Sambrisko bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap, 536234429Sambrisko sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb, 537234429Sambrisko &sc->mfi_tb_init_busaddr, 0); 538234429Sambrisko if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool, 539234429Sambrisko tb_mem_size)) { 540234429Sambrisko device_printf(sc->mfi_dev, 541234429Sambrisko "Thunderbolt pool preparation error\n"); 542234429Sambrisko return 0; 543234429Sambrisko } 544234429Sambrisko 545234429Sambrisko /* 546234429Sambrisko Allocate DMA memory mapping for MPI2 IOC Init descriptor, 547234429Sambrisko we are taking it diffrent from what we have allocated for Request 548234429Sambrisko and reply descriptors to avoid confusion later 549234429Sambrisko */ 550234429Sambrisko tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST); 551234429Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 552234429Sambrisko 1, 0, /* algnmnt, boundary */ 553234429Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 554234429Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 555234429Sambrisko NULL, NULL, /* filter, filterarg */ 556234429Sambrisko tb_mem_size, /* maxsize */ 557234429Sambrisko 1, /* msegments */ 558234429Sambrisko tb_mem_size, /* maxsegsize */ 559234429Sambrisko 0, /* flags */ 560234429Sambrisko NULL, NULL, /* lockfunc, lockarg */ 561234429Sambrisko &sc->mfi_tb_ioc_init_dmat)) { 562234429Sambrisko device_printf(sc->mfi_dev, 563234429Sambrisko "Cannot allocate comms DMA tag\n"); 564234429Sambrisko return (ENOMEM); 565234429Sambrisko } 566234429Sambrisko if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat, 567234429Sambrisko (void **)&sc->mfi_tb_ioc_init_desc, 568234429Sambrisko BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) { 569234429Sambrisko device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 570234429Sambrisko return (ENOMEM); 571234429Sambrisko } 572234429Sambrisko bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size); 573234429Sambrisko bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap, 574234429Sambrisko sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb, 575234429Sambrisko &sc->mfi_tb_ioc_init_busaddr, 0); 576234429Sambrisko } 577157114Sscottl /* 578157114Sscottl * Create the dma tag for data buffers. Used both for block I/O 579157114Sscottl * and for various internal data queries. 580157114Sscottl */ 581157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 582157114Sscottl 1, 0, /* algnmnt, boundary */ 583157114Sscottl BUS_SPACE_MAXADDR, /* lowaddr */ 584157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 585157114Sscottl NULL, NULL, /* filter, filterarg */ 586157114Sscottl BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 587162458Sscottl sc->mfi_max_sge, /* nsegments */ 588157114Sscottl BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 589157114Sscottl BUS_DMA_ALLOCNOW, /* flags */ 590157114Sscottl busdma_lock_mutex, /* lockfunc */ 591157114Sscottl &sc->mfi_io_lock, /* lockfuncarg */ 592157114Sscottl &sc->mfi_buffer_dmat)) { 593157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n"); 594157114Sscottl return (ENOMEM); 595157114Sscottl } 596157114Sscottl 597157114Sscottl /* 598157114Sscottl * Allocate DMA memory for the comms queues. Keep it under 4GB for 599157114Sscottl * efficiency. The mfi_hwcomms struct includes space for 1 reply queue 600157114Sscottl * entry, so the calculated size here will be will be 1 more than 601157114Sscottl * mfi_max_fw_cmds. This is apparently a requirement of the hardware. 602157114Sscottl */ 603157114Sscottl commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) + 604157114Sscottl sizeof(struct mfi_hwcomms); 605157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 606157114Sscottl 1, 0, /* algnmnt, boundary */ 607157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 608157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 609157114Sscottl NULL, NULL, /* filter, filterarg */ 610157114Sscottl commsz, /* maxsize */ 611157114Sscottl 1, /* msegments */ 612157114Sscottl commsz, /* maxsegsize */ 613157114Sscottl 0, /* flags */ 614157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 615157114Sscottl &sc->mfi_comms_dmat)) { 616157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n"); 617157114Sscottl return (ENOMEM); 618157114Sscottl } 619157114Sscottl if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms, 620157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) { 621157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 622157114Sscottl return (ENOMEM); 623157114Sscottl } 624157114Sscottl bzero(sc->mfi_comms, commsz); 625157114Sscottl bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap, 626234429Sambrisko sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0); 627157114Sscottl /* 628157114Sscottl * Allocate DMA memory for the command frames. Keep them in the 629162458Sscottl * lower 4GB for efficiency. Calculate the size of the commands at 630162458Sscottl * the same time; each command is one 64 byte frame plus a set of 631162458Sscottl * additional frames for holding sg lists or other data. 632157114Sscottl * The assumption here is that the SG list will start at the second 633162458Sscottl * frame and not use the unused bytes in the first frame. While this 634162458Sscottl * isn't technically correct, it simplifies the calculation and allows 635162458Sscottl * for command frames that might be larger than an mfi_io_frame. 636157114Sscottl */ 637157114Sscottl if (sizeof(bus_addr_t) == 8) { 638162458Sscottl sc->mfi_sge_size = sizeof(struct mfi_sg64); 639157114Sscottl sc->mfi_flags |= MFI_FLAGS_SG64; 640157114Sscottl } else { 641162458Sscottl sc->mfi_sge_size = sizeof(struct mfi_sg32); 642157114Sscottl } 643234429Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) 644234429Sambrisko sc->mfi_sge_size = sizeof(struct mfi_sg_skinny); 645162458Sscottl frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2; 646162458Sscottl sc->mfi_cmd_size = frames * MFI_FRAME_SIZE; 647162458Sscottl framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds; 648157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 649157114Sscottl 64, 0, /* algnmnt, boundary */ 650157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 651157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 652157114Sscottl NULL, NULL, /* filter, filterarg */ 653157114Sscottl framessz, /* maxsize */ 654157114Sscottl 1, /* nsegments */ 655157114Sscottl framessz, /* maxsegsize */ 656157114Sscottl 0, /* flags */ 657157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 658157114Sscottl &sc->mfi_frames_dmat)) { 659157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n"); 660157114Sscottl return (ENOMEM); 661157114Sscottl } 662157114Sscottl if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames, 663157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) { 664157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate frames memory\n"); 665157114Sscottl return (ENOMEM); 666157114Sscottl } 667157114Sscottl bzero(sc->mfi_frames, framessz); 668157114Sscottl bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap, 669234429Sambrisko sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0); 670157114Sscottl /* 671157114Sscottl * Allocate DMA memory for the frame sense data. Keep them in the 672157114Sscottl * lower 4GB for efficiency 673157114Sscottl */ 674157114Sscottl sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN; 675157114Sscottl if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 676157114Sscottl 4, 0, /* algnmnt, boundary */ 677157114Sscottl BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 678157114Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 679157114Sscottl NULL, NULL, /* filter, filterarg */ 680157114Sscottl sensesz, /* maxsize */ 681157114Sscottl 1, /* nsegments */ 682157114Sscottl sensesz, /* maxsegsize */ 683157114Sscottl 0, /* flags */ 684157114Sscottl NULL, NULL, /* lockfunc, lockarg */ 685157114Sscottl &sc->mfi_sense_dmat)) { 686157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n"); 687157114Sscottl return (ENOMEM); 688157114Sscottl } 689157114Sscottl if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense, 690157114Sscottl BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) { 691157114Sscottl device_printf(sc->mfi_dev, "Cannot allocate sense memory\n"); 692157114Sscottl return (ENOMEM); 693157114Sscottl } 694157114Sscottl bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap, 695234429Sambrisko sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0); 696157114Sscottl if ((error = mfi_alloc_commands(sc)) != 0) 697157114Sscottl return (error); 698157114Sscottl 699234429Sambrisko /* Before moving the FW to operational state, check whether 700234429Sambrisko * hostmemory is required by the FW or not 701234429Sambrisko */ 702157114Sscottl 703234429Sambrisko /* ThunderBolt MFI_IOC2 INIT */ 704234429Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 705234429Sambrisko sc->mfi_disable_intr(sc); 706250496Ssmh mtx_lock(&sc->mfi_io_lock); 707234429Sambrisko if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) { 708234429Sambrisko device_printf(sc->mfi_dev, 709234429Sambrisko "TB Init has failed with error %d\n",error); 710250496Ssmh mtx_unlock(&sc->mfi_io_lock); 711234429Sambrisko return error; 712234429Sambrisko } 713250496Ssmh mtx_unlock(&sc->mfi_io_lock); 714157114Sscottl 715234429Sambrisko if ((error = mfi_tbolt_alloc_cmd(sc)) != 0) 716234429Sambrisko return error; 717234429Sambrisko if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, 718234429Sambrisko INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc, 719234429Sambrisko &sc->mfi_intr)) { 720234429Sambrisko device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); 721234429Sambrisko return (EINVAL); 722234429Sambrisko } 723243824Sdelphij sc->mfi_intr_ptr = mfi_intr_tbolt; 724234429Sambrisko sc->mfi_enable_intr(sc); 725234429Sambrisko } else { 726234429Sambrisko if ((error = mfi_comms_init(sc)) != 0) 727234429Sambrisko return (error); 728157114Sscottl 729234429Sambrisko if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, 730234429Sambrisko INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) { 731234429Sambrisko device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); 732234429Sambrisko return (EINVAL); 733234429Sambrisko } 734243824Sdelphij sc->mfi_intr_ptr = mfi_intr; 735234429Sambrisko sc->mfi_enable_intr(sc); 736157114Sscottl } 737234429Sambrisko if ((error = mfi_get_controller_info(sc)) != 0) 738234429Sambrisko return (error); 739234429Sambrisko sc->disableOnlineCtrlReset = 0; 740157114Sscottl 741157114Sscottl /* Register a config hook to probe the bus for arrays */ 742157114Sscottl sc->mfi_ich.ich_func = mfi_startup; 743157114Sscottl sc->mfi_ich.ich_arg = sc; 744157114Sscottl if (config_intrhook_establish(&sc->mfi_ich) != 0) { 745157114Sscottl device_printf(sc->mfi_dev, "Cannot establish configuration " 746157114Sscottl "hook\n"); 747157114Sscottl return (EINVAL); 748157114Sscottl } 749250496Ssmh mtx_lock(&sc->mfi_io_lock); 750234429Sambrisko if ((error = mfi_aen_setup(sc, 0), 0) != 0) { 751234429Sambrisko mtx_unlock(&sc->mfi_io_lock); 752234429Sambrisko return (error); 753234429Sambrisko } 754250496Ssmh mtx_unlock(&sc->mfi_io_lock); 755157114Sscottl 756157114Sscottl /* 757157114Sscottl * Register a shutdown handler. 758157114Sscottl */ 759157114Sscottl if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown, 760157114Sscottl sc, SHUTDOWN_PRI_DEFAULT)) == NULL) { 761157114Sscottl device_printf(sc->mfi_dev, "Warning: shutdown event " 762157114Sscottl "registration failed\n"); 763157114Sscottl } 764157114Sscottl 765157114Sscottl /* 766157114Sscottl * Create the control device for doing management 767157114Sscottl */ 768157114Sscottl unit = device_get_unit(sc->mfi_dev); 769157114Sscottl sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR, 770157114Sscottl 0640, "mfi%d", unit); 771158737Sambrisko if (unit == 0) 772158737Sambrisko make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node"); 773157114Sscottl if (sc->mfi_cdev != NULL) 774157114Sscottl sc->mfi_cdev->si_drv1 = sc; 775171821Sjhb SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev), 776171821Sjhb SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), 777171821Sjhb OID_AUTO, "delete_busy_volumes", CTLFLAG_RW, 778171821Sjhb &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes"); 779171821Sjhb SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev), 780171821Sjhb SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), 781171821Sjhb OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW, 782171821Sjhb &sc->mfi_keep_deleted_volumes, 0, 783171821Sjhb "Don't detach the mfid device for a busy volume that is deleted"); 784157114Sscottl 785169611Sscottl device_add_child(sc->mfi_dev, "mfip", -1); 786169611Sscottl bus_generic_attach(sc->mfi_dev); 787169611Sscottl 788162619Sscottl /* Start the timeout watchdog */ 789178250Skris callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE); 790251406Ssmh callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz, 791162619Sscottl mfi_timeout, sc); 792162619Sscottl 793235135Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 794250496Ssmh mtx_lock(&sc->mfi_io_lock); 795235135Sambrisko mfi_tbolt_sync_map_info(sc); 796250496Ssmh mtx_unlock(&sc->mfi_io_lock); 797235135Sambrisko } 798235135Sambrisko 799157114Sscottl return (0); 800157114Sscottl} 801157114Sscottl 802157114Sscottlstatic int 803157114Sscottlmfi_alloc_commands(struct mfi_softc *sc) 804157114Sscottl{ 805157114Sscottl struct mfi_command *cm; 806250496Ssmh int i, j; 807157114Sscottl 808157114Sscottl /* 809157114Sscottl * XXX Should we allocate all the commands up front, or allocate on 810157114Sscottl * demand later like 'aac' does? 811157114Sscottl */ 812250496Ssmh sc->mfi_commands = malloc(sizeof(sc->mfi_commands[0]) * 813250496Ssmh sc->mfi_max_fw_cmds, M_MFIBUF, M_WAITOK | M_ZERO); 814178968Sscottl 815250496Ssmh for (i = 0; i < sc->mfi_max_fw_cmds; i++) { 816157114Sscottl cm = &sc->mfi_commands[i]; 817158737Sambrisko cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames + 818162458Sscottl sc->mfi_cmd_size * i); 819157114Sscottl cm->cm_frame_busaddr = sc->mfi_frames_busaddr + 820162458Sscottl sc->mfi_cmd_size * i; 821157114Sscottl cm->cm_frame->header.context = i; 822157114Sscottl cm->cm_sense = &sc->mfi_sense[i]; 823157114Sscottl cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i; 824157114Sscottl cm->cm_sc = sc; 825162619Sscottl cm->cm_index = i; 826157114Sscottl if (bus_dmamap_create(sc->mfi_buffer_dmat, 0, 827234429Sambrisko &cm->cm_dmamap) == 0) { 828234429Sambrisko mtx_lock(&sc->mfi_io_lock); 829157114Sscottl mfi_release_command(cm); 830234429Sambrisko mtx_unlock(&sc->mfi_io_lock); 831250496Ssmh } else { 832250496Ssmh device_printf(sc->mfi_dev, "Failed to allocate %d " 833250496Ssmh "command blocks, only allocated %d\n", 834250496Ssmh sc->mfi_max_fw_cmds, i - 1); 835250496Ssmh for (j = 0; j < i; j++) { 836250496Ssmh cm = &sc->mfi_commands[i]; 837250496Ssmh bus_dmamap_destroy(sc->mfi_buffer_dmat, 838250496Ssmh cm->cm_dmamap); 839250496Ssmh } 840250496Ssmh free(sc->mfi_commands, M_MFIBUF); 841250496Ssmh sc->mfi_commands = NULL; 842250496Ssmh 843250496Ssmh return (ENOMEM); 844234429Sambrisko } 845157114Sscottl } 846157114Sscottl 847157114Sscottl return (0); 848157114Sscottl} 849157114Sscottl 850169611Sscottlvoid 851157114Sscottlmfi_release_command(struct mfi_command *cm) 852157114Sscottl{ 853163398Sscottl struct mfi_frame_header *hdr; 854157114Sscottl uint32_t *hdr_data; 855157114Sscottl 856234429Sambrisko mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED); 857234429Sambrisko 858157114Sscottl /* 859157114Sscottl * Zero out the important fields of the frame, but make sure the 860165727Sscottl * context field is preserved. For efficiency, handle the fields 861165727Sscottl * as 32 bit words. Clear out the first S/G entry too for safety. 862157114Sscottl */ 863163398Sscottl hdr = &cm->cm_frame->header; 864175897Sambrisko if (cm->cm_data != NULL && hdr->sg_count) { 865163398Sscottl cm->cm_sg->sg32[0].len = 0; 866163398Sscottl cm->cm_sg->sg32[0].addr = 0; 867163398Sscottl } 868165727Sscottl 869250496Ssmh /* 870250496Ssmh * Command may be on other queues e.g. busy queue depending on the 871250496Ssmh * flow of a previous call to mfi_mapcmd, so ensure its dequeued 872250496Ssmh * properly 873250496Ssmh */ 874250496Ssmh if ((cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0) 875250496Ssmh mfi_remove_busy(cm); 876250496Ssmh if ((cm->cm_flags & MFI_ON_MFIQ_READY) != 0) 877250496Ssmh mfi_remove_ready(cm); 878250496Ssmh 879250496Ssmh /* We're not expecting it to be on any other queue but check */ 880250496Ssmh if ((cm->cm_flags & MFI_ON_MFIQ_MASK) != 0) { 881250496Ssmh panic("Command %p is still on another queue, flags = %#x", 882250496Ssmh cm, cm->cm_flags); 883250496Ssmh } 884250496Ssmh 885250496Ssmh /* tbolt cleanup */ 886250496Ssmh if ((cm->cm_flags & MFI_CMD_TBOLT) != 0) { 887250496Ssmh mfi_tbolt_return_cmd(cm->cm_sc, 888250496Ssmh cm->cm_sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames - 1], 889250496Ssmh cm); 890250496Ssmh } 891250496Ssmh 892165727Sscottl hdr_data = (uint32_t *)cm->cm_frame; 893165727Sscottl hdr_data[0] = 0; /* cmd, sense_len, cmd_status, scsi_status */ 894165727Sscottl hdr_data[1] = 0; /* target_id, lun_id, cdb_len, sg_count */ 895165727Sscottl hdr_data[4] = 0; /* flags, timeout */ 896165727Sscottl hdr_data[5] = 0; /* data_len */ 897165727Sscottl 898157114Sscottl cm->cm_extra_frames = 0; 899157114Sscottl cm->cm_flags = 0; 900157114Sscottl cm->cm_complete = NULL; 901157114Sscottl cm->cm_private = NULL; 902169611Sscottl cm->cm_data = NULL; 903157114Sscottl cm->cm_sg = 0; 904157114Sscottl cm->cm_total_frame_size = 0; 905234429Sambrisko cm->retry_for_fw_reset = 0; 906163398Sscottl 907157114Sscottl mfi_enqueue_free(cm); 908157114Sscottl} 909157114Sscottl 910235135Sambriskoint 911234429Sambriskomfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, 912234429Sambrisko uint32_t opcode, void **bufp, size_t bufsize) 913159806Sps{ 914159806Sps struct mfi_command *cm; 915159806Sps struct mfi_dcmd_frame *dcmd; 916159806Sps void *buf = NULL; 917234429Sambrisko uint32_t context = 0; 918234429Sambrisko 919159806Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 920234429Sambrisko 921159806Sps cm = mfi_dequeue_free(sc); 922159806Sps if (cm == NULL) 923159806Sps return (EBUSY); 924159806Sps 925234429Sambrisko /* Zero out the MFI frame */ 926234429Sambrisko context = cm->cm_frame->header.context; 927234429Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 928234429Sambrisko cm->cm_frame->header.context = context; 929234429Sambrisko 930159806Sps if ((bufsize > 0) && (bufp != NULL)) { 931159806Sps if (*bufp == NULL) { 932159806Sps buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO); 933159806Sps if (buf == NULL) { 934159806Sps mfi_release_command(cm); 935159806Sps return (ENOMEM); 936159806Sps } 937159806Sps *bufp = buf; 938159806Sps } else { 939159806Sps buf = *bufp; 940159806Sps } 941159806Sps } 942159806Sps 943159806Sps dcmd = &cm->cm_frame->dcmd; 944159806Sps bzero(dcmd->mbox, MFI_MBOX_SIZE); 945159806Sps dcmd->header.cmd = MFI_CMD_DCMD; 946159806Sps dcmd->header.timeout = 0; 947159806Sps dcmd->header.flags = 0; 948159806Sps dcmd->header.data_len = bufsize; 949234429Sambrisko dcmd->header.scsi_status = 0; 950159806Sps dcmd->opcode = opcode; 951159806Sps cm->cm_sg = &dcmd->sgl; 952159806Sps cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 953159806Sps cm->cm_flags = 0; 954159806Sps cm->cm_data = buf; 955159806Sps cm->cm_private = buf; 956159806Sps cm->cm_len = bufsize; 957159806Sps 958159806Sps *cmp = cm; 959159806Sps if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL)) 960159806Sps *bufp = buf; 961159806Sps return (0); 962159806Sps} 963159806Sps 964159806Spsstatic int 965157114Sscottlmfi_comms_init(struct mfi_softc *sc) 966157114Sscottl{ 967157114Sscottl struct mfi_command *cm; 968157114Sscottl struct mfi_init_frame *init; 969157114Sscottl struct mfi_init_qinfo *qinfo; 970157114Sscottl int error; 971234429Sambrisko uint32_t context = 0; 972157114Sscottl 973163398Sscottl mtx_lock(&sc->mfi_io_lock); 974250496Ssmh if ((cm = mfi_dequeue_free(sc)) == NULL) { 975250496Ssmh mtx_unlock(&sc->mfi_io_lock); 976157114Sscottl return (EBUSY); 977250496Ssmh } 978157114Sscottl 979234429Sambrisko /* Zero out the MFI frame */ 980234429Sambrisko context = cm->cm_frame->header.context; 981234429Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 982234429Sambrisko cm->cm_frame->header.context = context; 983234429Sambrisko 984157114Sscottl /* 985157114Sscottl * Abuse the SG list area of the frame to hold the init_qinfo 986157114Sscottl * object; 987157114Sscottl */ 988157114Sscottl init = &cm->cm_frame->init; 989157114Sscottl qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE); 990157114Sscottl 991157114Sscottl bzero(qinfo, sizeof(struct mfi_init_qinfo)); 992157114Sscottl qinfo->rq_entries = sc->mfi_max_fw_cmds + 1; 993157114Sscottl qinfo->rq_addr_lo = sc->mfi_comms_busaddr + 994157114Sscottl offsetof(struct mfi_hwcomms, hw_reply_q); 995157114Sscottl qinfo->pi_addr_lo = sc->mfi_comms_busaddr + 996157114Sscottl offsetof(struct mfi_hwcomms, hw_pi); 997157114Sscottl qinfo->ci_addr_lo = sc->mfi_comms_busaddr + 998157114Sscottl offsetof(struct mfi_hwcomms, hw_ci); 999157114Sscottl 1000157114Sscottl init->header.cmd = MFI_CMD_INIT; 1001157114Sscottl init->header.data_len = sizeof(struct mfi_init_qinfo); 1002157114Sscottl init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE; 1003164375Sscottl cm->cm_data = NULL; 1004164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 1005157114Sscottl 1006250496Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) 1007157114Sscottl device_printf(sc->mfi_dev, "failed to send init command\n"); 1008157114Sscottl mfi_release_command(cm); 1009163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1010157114Sscottl 1011250496Ssmh return (error); 1012157114Sscottl} 1013157114Sscottl 1014157114Sscottlstatic int 1015157114Sscottlmfi_get_controller_info(struct mfi_softc *sc) 1016157114Sscottl{ 1017159806Sps struct mfi_command *cm = NULL; 1018159806Sps struct mfi_ctrl_info *ci = NULL; 1019157114Sscottl uint32_t max_sectors_1, max_sectors_2; 1020157114Sscottl int error; 1021157114Sscottl 1022159806Sps mtx_lock(&sc->mfi_io_lock); 1023159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO, 1024159806Sps (void **)&ci, sizeof(*ci)); 1025159806Sps if (error) 1026159806Sps goto out; 1027157114Sscottl cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1028157114Sscottl 1029157114Sscottl if ((error = mfi_mapcmd(sc, cm)) != 0) { 1030157114Sscottl device_printf(sc->mfi_dev, "Failed to get controller info\n"); 1031162458Sscottl sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE / 1032157114Sscottl MFI_SECTOR_LEN; 1033159806Sps error = 0; 1034159806Sps goto out; 1035157114Sscottl } 1036157114Sscottl 1037157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1038157114Sscottl BUS_DMASYNC_POSTREAD); 1039157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1040157114Sscottl 1041234429Sambrisko max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io; 1042157114Sscottl max_sectors_2 = ci->max_request_size; 1043157114Sscottl sc->mfi_max_io = min(max_sectors_1, max_sectors_2); 1044234429Sambrisko sc->disableOnlineCtrlReset = 1045234429Sambrisko ci->properties.OnOffProperties.disableOnlineCtrlReset; 1046157114Sscottl 1047159806Spsout: 1048159806Sps if (ci) 1049159806Sps free(ci, M_MFIBUF); 1050159806Sps if (cm) 1051159806Sps mfi_release_command(cm); 1052159806Sps mtx_unlock(&sc->mfi_io_lock); 1053157114Sscottl return (error); 1054157114Sscottl} 1055157114Sscottl 1056157114Sscottlstatic int 1057159806Spsmfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state) 1058158737Sambrisko{ 1059159812Sps struct mfi_command *cm = NULL; 1060158737Sambrisko int error; 1061158737Sambrisko 1062250496Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1063159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO, 1064159806Sps (void **)log_state, sizeof(**log_state)); 1065159806Sps if (error) 1066159806Sps goto out; 1067159810Sps cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1068158737Sambrisko 1069158737Sambrisko if ((error = mfi_mapcmd(sc, cm)) != 0) { 1070159802Sps device_printf(sc->mfi_dev, "Failed to get log state\n"); 1071159806Sps goto out; 1072158737Sambrisko } 1073158737Sambrisko 1074158737Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1075158737Sambrisko BUS_DMASYNC_POSTREAD); 1076158737Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1077158737Sambrisko 1078159806Spsout: 1079159812Sps if (cm) 1080159812Sps mfi_release_command(cm); 1081158737Sambrisko 1082158737Sambrisko return (error); 1083158737Sambrisko} 1084158737Sambrisko 1085234429Sambriskoint 1086158737Sambriskomfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start) 1087158737Sambrisko{ 1088159806Sps struct mfi_evt_log_state *log_state = NULL; 1089158737Sambrisko union mfi_evt class_locale; 1090158737Sambrisko int error = 0; 1091158737Sambrisko uint32_t seq; 1092158737Sambrisko 1093250496Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1094250496Ssmh 1095158737Sambrisko class_locale.members.reserved = 0; 1096162118Sambrisko class_locale.members.locale = mfi_event_locale; 1097222589Semaste class_locale.members.evt_class = mfi_event_class; 1098158737Sambrisko 1099158737Sambrisko if (seq_start == 0) { 1100250496Ssmh if ((error = mfi_get_log_state(sc, &log_state)) != 0) 1101250496Ssmh goto out; 1102234429Sambrisko sc->mfi_boot_seq_num = log_state->boot_seq_num; 1103180037Sjhb 1104180037Sjhb /* 1105180037Sjhb * Walk through any events that fired since the last 1106180037Sjhb * shutdown. 1107180037Sjhb */ 1108250496Ssmh if ((error = mfi_parse_entries(sc, log_state->shutdown_seq_num, 1109250496Ssmh log_state->newest_seq_num)) != 0) 1110250496Ssmh goto out; 1111180037Sjhb seq = log_state->newest_seq_num; 1112158737Sambrisko } else 1113158737Sambrisko seq = seq_start; 1114250496Ssmh error = mfi_aen_register(sc, seq, class_locale.word); 1115250496Ssmhout: 1116159806Sps free(log_state, M_MFIBUF); 1117158737Sambrisko 1118250496Ssmh return (error); 1119158737Sambrisko} 1120158737Sambrisko 1121234429Sambriskoint 1122159811Spsmfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm) 1123159811Sps{ 1124159811Sps 1125159811Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1126159811Sps cm->cm_complete = NULL; 1127159811Sps 1128170284Sambrisko /* 1129170284Sambrisko * MegaCli can issue a DCMD of 0. In this case do nothing 1130170284Sambrisko * and return 0 to it as status 1131170284Sambrisko */ 1132170284Sambrisko if (cm->cm_frame->dcmd.opcode == 0) { 1133170284Sambrisko cm->cm_frame->header.cmd_status = MFI_STAT_OK; 1134170284Sambrisko cm->cm_error = 0; 1135170284Sambrisko return (cm->cm_error); 1136170284Sambrisko } 1137159811Sps mfi_enqueue_ready(cm); 1138159811Sps mfi_startio(sc); 1139170284Sambrisko if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0) 1140170284Sambrisko msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0); 1141170284Sambrisko return (cm->cm_error); 1142159811Sps} 1143159811Sps 1144157114Sscottlvoid 1145157114Sscottlmfi_free(struct mfi_softc *sc) 1146157114Sscottl{ 1147157114Sscottl struct mfi_command *cm; 1148157114Sscottl int i; 1149157114Sscottl 1150162619Sscottl callout_drain(&sc->mfi_watchdog_callout); 1151162619Sscottl 1152157114Sscottl if (sc->mfi_cdev != NULL) 1153157114Sscottl destroy_dev(sc->mfi_cdev); 1154157114Sscottl 1155250496Ssmh if (sc->mfi_commands != NULL) { 1156250496Ssmh for (i = 0; i < sc->mfi_max_fw_cmds; i++) { 1157157114Sscottl cm = &sc->mfi_commands[i]; 1158157114Sscottl bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap); 1159157114Sscottl } 1160157114Sscottl free(sc->mfi_commands, M_MFIBUF); 1161250496Ssmh sc->mfi_commands = NULL; 1162157114Sscottl } 1163157114Sscottl 1164157114Sscottl if (sc->mfi_intr) 1165157114Sscottl bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr); 1166157114Sscottl if (sc->mfi_irq != NULL) 1167157114Sscottl bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid, 1168157114Sscottl sc->mfi_irq); 1169157114Sscottl 1170157114Sscottl if (sc->mfi_sense_busaddr != 0) 1171157114Sscottl bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap); 1172157114Sscottl if (sc->mfi_sense != NULL) 1173157114Sscottl bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense, 1174157114Sscottl sc->mfi_sense_dmamap); 1175157114Sscottl if (sc->mfi_sense_dmat != NULL) 1176157114Sscottl bus_dma_tag_destroy(sc->mfi_sense_dmat); 1177157114Sscottl 1178157114Sscottl if (sc->mfi_frames_busaddr != 0) 1179157114Sscottl bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap); 1180157114Sscottl if (sc->mfi_frames != NULL) 1181157114Sscottl bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames, 1182157114Sscottl sc->mfi_frames_dmamap); 1183157114Sscottl if (sc->mfi_frames_dmat != NULL) 1184157114Sscottl bus_dma_tag_destroy(sc->mfi_frames_dmat); 1185157114Sscottl 1186157114Sscottl if (sc->mfi_comms_busaddr != 0) 1187157114Sscottl bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap); 1188157114Sscottl if (sc->mfi_comms != NULL) 1189157114Sscottl bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms, 1190157114Sscottl sc->mfi_comms_dmamap); 1191157114Sscottl if (sc->mfi_comms_dmat != NULL) 1192157114Sscottl bus_dma_tag_destroy(sc->mfi_comms_dmat); 1193157114Sscottl 1194234429Sambrisko /* ThunderBolt contiguous memory free here */ 1195234429Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 1196234429Sambrisko if (sc->mfi_tb_busaddr != 0) 1197234429Sambrisko bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap); 1198234429Sambrisko if (sc->request_message_pool != NULL) 1199234429Sambrisko bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool, 1200234429Sambrisko sc->mfi_tb_dmamap); 1201234429Sambrisko if (sc->mfi_tb_dmat != NULL) 1202234429Sambrisko bus_dma_tag_destroy(sc->mfi_tb_dmat); 1203234429Sambrisko 1204234429Sambrisko /* Version buffer memory free */ 1205234429Sambrisko /* Start LSIP200113393 */ 1206234429Sambrisko if (sc->verbuf_h_busaddr != 0) 1207234429Sambrisko bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap); 1208234429Sambrisko if (sc->verbuf != NULL) 1209234429Sambrisko bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf, 1210234429Sambrisko sc->verbuf_h_dmamap); 1211234429Sambrisko if (sc->verbuf_h_dmat != NULL) 1212234429Sambrisko bus_dma_tag_destroy(sc->verbuf_h_dmat); 1213234429Sambrisko 1214234429Sambrisko /* End LSIP200113393 */ 1215234429Sambrisko /* ThunderBolt INIT packet memory Free */ 1216234429Sambrisko if (sc->mfi_tb_init_busaddr != 0) 1217250496Ssmh bus_dmamap_unload(sc->mfi_tb_init_dmat, 1218250496Ssmh sc->mfi_tb_init_dmamap); 1219234429Sambrisko if (sc->mfi_tb_init != NULL) 1220234429Sambrisko bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init, 1221234429Sambrisko sc->mfi_tb_init_dmamap); 1222234429Sambrisko if (sc->mfi_tb_init_dmat != NULL) 1223234429Sambrisko bus_dma_tag_destroy(sc->mfi_tb_init_dmat); 1224234429Sambrisko 1225234429Sambrisko /* ThunderBolt IOC Init Desc memory free here */ 1226234429Sambrisko if (sc->mfi_tb_ioc_init_busaddr != 0) 1227234429Sambrisko bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat, 1228234429Sambrisko sc->mfi_tb_ioc_init_dmamap); 1229234429Sambrisko if (sc->mfi_tb_ioc_init_desc != NULL) 1230234429Sambrisko bus_dmamem_free(sc->mfi_tb_ioc_init_dmat, 1231234429Sambrisko sc->mfi_tb_ioc_init_desc, 1232234429Sambrisko sc->mfi_tb_ioc_init_dmamap); 1233234429Sambrisko if (sc->mfi_tb_ioc_init_dmat != NULL) 1234234429Sambrisko bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat); 1235250496Ssmh if (sc->mfi_cmd_pool_tbolt != NULL) { 1236250496Ssmh for (int i = 0; i < sc->mfi_max_fw_cmds; i++) { 1237234429Sambrisko if (sc->mfi_cmd_pool_tbolt[i] != NULL) { 1238234429Sambrisko free(sc->mfi_cmd_pool_tbolt[i], 1239234429Sambrisko M_MFIBUF); 1240234429Sambrisko sc->mfi_cmd_pool_tbolt[i] = NULL; 1241234429Sambrisko } 1242234429Sambrisko } 1243234429Sambrisko free(sc->mfi_cmd_pool_tbolt, M_MFIBUF); 1244234429Sambrisko sc->mfi_cmd_pool_tbolt = NULL; 1245234429Sambrisko } 1246234429Sambrisko if (sc->request_desc_pool != NULL) { 1247234429Sambrisko free(sc->request_desc_pool, M_MFIBUF); 1248234429Sambrisko sc->request_desc_pool = NULL; 1249234429Sambrisko } 1250234429Sambrisko } 1251157114Sscottl if (sc->mfi_buffer_dmat != NULL) 1252157114Sscottl bus_dma_tag_destroy(sc->mfi_buffer_dmat); 1253157114Sscottl if (sc->mfi_parent_dmat != NULL) 1254157114Sscottl bus_dma_tag_destroy(sc->mfi_parent_dmat); 1255157114Sscottl 1256171821Sjhb if (mtx_initialized(&sc->mfi_io_lock)) { 1257157114Sscottl mtx_destroy(&sc->mfi_io_lock); 1258171821Sjhb sx_destroy(&sc->mfi_config_lock); 1259171821Sjhb } 1260157114Sscottl 1261157114Sscottl return; 1262157114Sscottl} 1263157114Sscottl 1264157114Sscottlstatic void 1265157114Sscottlmfi_startup(void *arg) 1266157114Sscottl{ 1267157114Sscottl struct mfi_softc *sc; 1268157114Sscottl 1269157114Sscottl sc = (struct mfi_softc *)arg; 1270157114Sscottl 1271157114Sscottl config_intrhook_disestablish(&sc->mfi_ich); 1272157114Sscottl 1273171980Sscottl sc->mfi_enable_intr(sc); 1274171821Sjhb sx_xlock(&sc->mfi_config_lock); 1275163398Sscottl mtx_lock(&sc->mfi_io_lock); 1276159811Sps mfi_ldprobe(sc); 1277234429Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) 1278234429Sambrisko mfi_syspdprobe(sc); 1279163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1280171821Sjhb sx_xunlock(&sc->mfi_config_lock); 1281157114Sscottl} 1282157114Sscottl 1283157114Sscottlstatic void 1284157114Sscottlmfi_intr(void *arg) 1285157114Sscottl{ 1286157114Sscottl struct mfi_softc *sc; 1287157114Sscottl struct mfi_command *cm; 1288171980Sscottl uint32_t pi, ci, context; 1289157114Sscottl 1290157114Sscottl sc = (struct mfi_softc *)arg; 1291157114Sscottl 1292171980Sscottl if (sc->mfi_check_clear_intr(sc)) 1293157114Sscottl return; 1294163398Sscottl 1295234429Sambriskorestart: 1296157114Sscottl pi = sc->mfi_comms->hw_pi; 1297157114Sscottl ci = sc->mfi_comms->hw_ci; 1298157114Sscottl mtx_lock(&sc->mfi_io_lock); 1299157114Sscottl while (ci != pi) { 1300157114Sscottl context = sc->mfi_comms->hw_reply_q[ci]; 1301170284Sambrisko if (context < sc->mfi_max_fw_cmds) { 1302170284Sambrisko cm = &sc->mfi_commands[context]; 1303170284Sambrisko mfi_remove_busy(cm); 1304170284Sambrisko cm->cm_error = 0; 1305170284Sambrisko mfi_complete(sc, cm); 1306170284Sambrisko } 1307250496Ssmh if (++ci == (sc->mfi_max_fw_cmds + 1)) 1308157114Sscottl ci = 0; 1309157114Sscottl } 1310157114Sscottl 1311157114Sscottl sc->mfi_comms->hw_ci = ci; 1312157114Sscottl 1313163398Sscottl /* Give defered I/O a chance to run */ 1314250496Ssmh sc->mfi_flags &= ~MFI_FLAGS_QFRZN; 1315163398Sscottl mfi_startio(sc); 1316163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1317163398Sscottl 1318234429Sambrisko /* 1319234429Sambrisko * Dummy read to flush the bus; this ensures that the indexes are up 1320234429Sambrisko * to date. Restart processing if more commands have come it. 1321234429Sambrisko */ 1322234429Sambrisko (void)sc->mfi_read_fw_status(sc); 1323234429Sambrisko if (pi != sc->mfi_comms->hw_pi) 1324234429Sambrisko goto restart; 1325234429Sambrisko 1326157114Sscottl return; 1327157114Sscottl} 1328157114Sscottl 1329157114Sscottlint 1330157114Sscottlmfi_shutdown(struct mfi_softc *sc) 1331157114Sscottl{ 1332157114Sscottl struct mfi_dcmd_frame *dcmd; 1333157114Sscottl struct mfi_command *cm; 1334157114Sscottl int error; 1335157114Sscottl 1336243824Sdelphij 1337250496Ssmh if (sc->mfi_aen_cm != NULL) { 1338243824Sdelphij sc->cm_aen_abort = 1; 1339243824Sdelphij mfi_abort(sc, &sc->mfi_aen_cm); 1340250496Ssmh } 1341243824Sdelphij 1342250496Ssmh if (sc->mfi_map_sync_cm != NULL) { 1343243824Sdelphij sc->cm_map_abort = 1; 1344243824Sdelphij mfi_abort(sc, &sc->mfi_map_sync_cm); 1345250496Ssmh } 1346243824Sdelphij 1347159806Sps mtx_lock(&sc->mfi_io_lock); 1348159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0); 1349163398Sscottl if (error) { 1350163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1351159806Sps return (error); 1352163398Sscottl } 1353157114Sscottl 1354157114Sscottl dcmd = &cm->cm_frame->dcmd; 1355157114Sscottl dcmd->header.flags = MFI_FRAME_DIR_NONE; 1356164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 1357164375Sscottl cm->cm_data = NULL; 1358157114Sscottl 1359250496Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) 1360157114Sscottl device_printf(sc->mfi_dev, "Failed to shutdown controller\n"); 1361157114Sscottl 1362159812Sps mfi_release_command(cm); 1363163398Sscottl mtx_unlock(&sc->mfi_io_lock); 1364157114Sscottl return (error); 1365157114Sscottl} 1366157114Sscottl 1367157114Sscottlstatic void 1368234429Sambriskomfi_syspdprobe(struct mfi_softc *sc) 1369234429Sambrisko{ 1370234429Sambrisko struct mfi_frame_header *hdr; 1371234429Sambrisko struct mfi_command *cm = NULL; 1372234429Sambrisko struct mfi_pd_list *pdlist = NULL; 1373234429Sambrisko struct mfi_system_pd *syspd, *tmp; 1374243824Sdelphij struct mfi_system_pending *syspd_pend; 1375234429Sambrisko int error, i, found; 1376234429Sambrisko 1377234429Sambrisko sx_assert(&sc->mfi_config_lock, SA_XLOCKED); 1378234429Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1379234429Sambrisko /* Add SYSTEM PD's */ 1380234429Sambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY, 1381234429Sambrisko (void **)&pdlist, sizeof(*pdlist)); 1382235135Sambrisko if (error) { 1383234429Sambrisko device_printf(sc->mfi_dev, 1384234429Sambrisko "Error while forming SYSTEM PD list\n"); 1385234429Sambrisko goto out; 1386234429Sambrisko } 1387234429Sambrisko 1388234429Sambrisko cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1389234429Sambrisko cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST; 1390234429Sambrisko cm->cm_frame->dcmd.mbox[1] = 0; 1391234429Sambrisko if (mfi_mapcmd(sc, cm) != 0) { 1392234429Sambrisko device_printf(sc->mfi_dev, 1393234429Sambrisko "Failed to get syspd device listing\n"); 1394234429Sambrisko goto out; 1395234429Sambrisko } 1396234429Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap, 1397234429Sambrisko BUS_DMASYNC_POSTREAD); 1398234429Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1399234429Sambrisko hdr = &cm->cm_frame->header; 1400234429Sambrisko if (hdr->cmd_status != MFI_STAT_OK) { 1401234429Sambrisko device_printf(sc->mfi_dev, 1402234429Sambrisko "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status); 1403234429Sambrisko goto out; 1404234429Sambrisko } 1405234429Sambrisko /* Get each PD and add it to the system */ 1406234429Sambrisko for (i = 0; i < pdlist->count; i++) { 1407234429Sambrisko if (pdlist->addr[i].device_id == 1408234429Sambrisko pdlist->addr[i].encl_device_id) 1409234429Sambrisko continue; 1410234429Sambrisko found = 0; 1411234429Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { 1412234429Sambrisko if (syspd->pd_id == pdlist->addr[i].device_id) 1413234429Sambrisko found = 1; 1414234429Sambrisko } 1415243824Sdelphij TAILQ_FOREACH(syspd_pend, &sc->mfi_syspd_pend_tqh, pd_link) { 1416243824Sdelphij if (syspd_pend->pd_id == pdlist->addr[i].device_id) 1417243824Sdelphij found = 1; 1418243824Sdelphij } 1419234429Sambrisko if (found == 0) 1420234429Sambrisko mfi_add_sys_pd(sc, pdlist->addr[i].device_id); 1421234429Sambrisko } 1422234429Sambrisko /* Delete SYSPD's whose state has been changed */ 1423234429Sambrisko TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) { 1424234429Sambrisko found = 0; 1425234429Sambrisko for (i = 0; i < pdlist->count; i++) { 1426250496Ssmh if (syspd->pd_id == pdlist->addr[i].device_id) { 1427234429Sambrisko found = 1; 1428250496Ssmh break; 1429250496Ssmh } 1430234429Sambrisko } 1431234429Sambrisko if (found == 0) { 1432234429Sambrisko printf("DELETE\n"); 1433234429Sambrisko mtx_unlock(&sc->mfi_io_lock); 1434234429Sambrisko mtx_lock(&Giant); 1435234429Sambrisko device_delete_child(sc->mfi_dev, syspd->pd_dev); 1436234429Sambrisko mtx_unlock(&Giant); 1437234429Sambrisko mtx_lock(&sc->mfi_io_lock); 1438234429Sambrisko } 1439234429Sambrisko } 1440234429Sambriskoout: 1441234429Sambrisko if (pdlist) 1442234429Sambrisko free(pdlist, M_MFIBUF); 1443234429Sambrisko if (cm) 1444234429Sambrisko mfi_release_command(cm); 1445234429Sambrisko 1446234429Sambrisko return; 1447234429Sambrisko} 1448234429Sambrisko 1449234429Sambriskostatic void 1450159811Spsmfi_ldprobe(struct mfi_softc *sc) 1451157114Sscottl{ 1452159811Sps struct mfi_frame_header *hdr; 1453159811Sps struct mfi_command *cm = NULL; 1454159811Sps struct mfi_ld_list *list = NULL; 1455171821Sjhb struct mfi_disk *ld; 1456243824Sdelphij struct mfi_disk_pending *ld_pend; 1457159811Sps int error, i; 1458157114Sscottl 1459171821Sjhb sx_assert(&sc->mfi_config_lock, SA_XLOCKED); 1460163398Sscottl mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1461163398Sscottl 1462159811Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST, 1463159811Sps (void **)&list, sizeof(*list)); 1464159811Sps if (error) 1465159811Sps goto out; 1466159811Sps 1467159811Sps cm->cm_flags = MFI_CMD_DATAIN; 1468159811Sps if (mfi_wait_command(sc, cm) != 0) { 1469159811Sps device_printf(sc->mfi_dev, "Failed to get device listing\n"); 1470159811Sps goto out; 1471157114Sscottl } 1472157114Sscottl 1473157114Sscottl hdr = &cm->cm_frame->header; 1474159811Sps if (hdr->cmd_status != MFI_STAT_OK) { 1475159811Sps device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n", 1476159811Sps hdr->cmd_status); 1477159811Sps goto out; 1478157114Sscottl } 1479157114Sscottl 1480171821Sjhb for (i = 0; i < list->ld_count; i++) { 1481171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 1482171821Sjhb if (ld->ld_id == list->ld_list[i].ld.v.target_id) 1483171821Sjhb goto skip_add; 1484171821Sjhb } 1485243824Sdelphij TAILQ_FOREACH(ld_pend, &sc->mfi_ld_pend_tqh, ld_link) { 1486243824Sdelphij if (ld_pend->ld_id == list->ld_list[i].ld.v.target_id) 1487243824Sdelphij goto skip_add; 1488243824Sdelphij } 1489163398Sscottl mfi_add_ld(sc, list->ld_list[i].ld.v.target_id); 1490171821Sjhb skip_add:; 1491171821Sjhb } 1492159811Spsout: 1493159811Sps if (list) 1494159811Sps free(list, M_MFIBUF); 1495159811Sps if (cm) 1496157114Sscottl mfi_release_command(cm); 1497163398Sscottl 1498159811Sps return; 1499157114Sscottl} 1500157114Sscottl 1501180038Sjhb/* 1502180038Sjhb * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If 1503180038Sjhb * the bits in 24-31 are all set, then it is the number of seconds since 1504180038Sjhb * boot. 1505180038Sjhb */ 1506180038Sjhbstatic const char * 1507180038Sjhbformat_timestamp(uint32_t timestamp) 1508158737Sambrisko{ 1509180038Sjhb static char buffer[32]; 1510180038Sjhb 1511180038Sjhb if ((timestamp & 0xff000000) == 0xff000000) 1512180038Sjhb snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & 1513180038Sjhb 0x00ffffff); 1514180038Sjhb else 1515180038Sjhb snprintf(buffer, sizeof(buffer), "%us", timestamp); 1516180038Sjhb return (buffer); 1517180038Sjhb} 1518180038Sjhb 1519180038Sjhbstatic const char * 1520180038Sjhbformat_class(int8_t class) 1521180038Sjhb{ 1522180038Sjhb static char buffer[6]; 1523180038Sjhb 1524180038Sjhb switch (class) { 1525180038Sjhb case MFI_EVT_CLASS_DEBUG: 1526180038Sjhb return ("debug"); 1527180038Sjhb case MFI_EVT_CLASS_PROGRESS: 1528180038Sjhb return ("progress"); 1529180038Sjhb case MFI_EVT_CLASS_INFO: 1530180038Sjhb return ("info"); 1531180038Sjhb case MFI_EVT_CLASS_WARNING: 1532180038Sjhb return ("WARN"); 1533180038Sjhb case MFI_EVT_CLASS_CRITICAL: 1534180038Sjhb return ("CRIT"); 1535180038Sjhb case MFI_EVT_CLASS_FATAL: 1536180038Sjhb return ("FATAL"); 1537180038Sjhb case MFI_EVT_CLASS_DEAD: 1538180038Sjhb return ("DEAD"); 1539158737Sambrisko default: 1540180038Sjhb snprintf(buffer, sizeof(buffer), "%d", class); 1541180038Sjhb return (buffer); 1542158737Sambrisko } 1543158737Sambrisko} 1544158737Sambrisko 1545180038Sjhbstatic void 1546180038Sjhbmfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) 1547180038Sjhb{ 1548234429Sambrisko struct mfi_system_pd *syspd = NULL; 1549180038Sjhb 1550200238Sjkim device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq, 1551222589Semaste format_timestamp(detail->time), detail->evt_class.members.locale, 1552234429Sambrisko format_class(detail->evt_class.members.evt_class), 1553234429Sambrisko detail->description); 1554234429Sambrisko 1555234429Sambrisko /* Don't act on old AEN's or while shutting down */ 1556234429Sambrisko if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching) 1557234429Sambrisko return; 1558234429Sambrisko 1559234429Sambrisko switch (detail->arg_type) { 1560234429Sambrisko case MR_EVT_ARGS_NONE: 1561234429Sambrisko if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) { 1562234429Sambrisko device_printf(sc->mfi_dev, "HostBus scan raised\n"); 1563234429Sambrisko if (mfi_detect_jbod_change) { 1564234429Sambrisko /* 1565234429Sambrisko * Probe for new SYSPD's and Delete 1566234429Sambrisko * invalid SYSPD's 1567234429Sambrisko */ 1568234429Sambrisko sx_xlock(&sc->mfi_config_lock); 1569234429Sambrisko mtx_lock(&sc->mfi_io_lock); 1570234429Sambrisko mfi_syspdprobe(sc); 1571234429Sambrisko mtx_unlock(&sc->mfi_io_lock); 1572234429Sambrisko sx_xunlock(&sc->mfi_config_lock); 1573234429Sambrisko } 1574234429Sambrisko } 1575234429Sambrisko break; 1576234429Sambrisko case MR_EVT_ARGS_LD_STATE: 1577234429Sambrisko /* During load time driver reads all the events starting 1578234429Sambrisko * from the one that has been logged after shutdown. Avoid 1579234429Sambrisko * these old events. 1580234429Sambrisko */ 1581234429Sambrisko if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) { 1582234429Sambrisko /* Remove the LD */ 1583234429Sambrisko struct mfi_disk *ld; 1584234429Sambrisko TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 1585234429Sambrisko if (ld->ld_id == 1586234429Sambrisko detail->args.ld_state.ld.target_id) 1587234429Sambrisko break; 1588234429Sambrisko } 1589234429Sambrisko /* 1590234429Sambrisko Fix: for kernel panics when SSCD is removed 1591234429Sambrisko KASSERT(ld != NULL, ("volume dissappeared")); 1592234429Sambrisko */ 1593234429Sambrisko if (ld != NULL) { 1594234429Sambrisko mtx_lock(&Giant); 1595234429Sambrisko device_delete_child(sc->mfi_dev, ld->ld_dev); 1596234429Sambrisko mtx_unlock(&Giant); 1597234429Sambrisko } 1598234429Sambrisko } 1599234429Sambrisko break; 1600234429Sambrisko case MR_EVT_ARGS_PD: 1601234429Sambrisko if (detail->code == MR_EVT_PD_REMOVED) { 1602234429Sambrisko if (mfi_detect_jbod_change) { 1603234429Sambrisko /* 1604234429Sambrisko * If the removed device is a SYSPD then 1605234429Sambrisko * delete it 1606234429Sambrisko */ 1607234429Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, 1608234429Sambrisko pd_link) { 1609234429Sambrisko if (syspd->pd_id == 1610234429Sambrisko detail->args.pd.device_id) { 1611234429Sambrisko mtx_lock(&Giant); 1612234429Sambrisko device_delete_child( 1613234429Sambrisko sc->mfi_dev, 1614234429Sambrisko syspd->pd_dev); 1615234429Sambrisko mtx_unlock(&Giant); 1616234429Sambrisko break; 1617234429Sambrisko } 1618234429Sambrisko } 1619234429Sambrisko } 1620234429Sambrisko } 1621234429Sambrisko if (detail->code == MR_EVT_PD_INSERTED) { 1622234429Sambrisko if (mfi_detect_jbod_change) { 1623234429Sambrisko /* Probe for new SYSPD's */ 1624234429Sambrisko sx_xlock(&sc->mfi_config_lock); 1625234429Sambrisko mtx_lock(&sc->mfi_io_lock); 1626234429Sambrisko mfi_syspdprobe(sc); 1627234429Sambrisko mtx_unlock(&sc->mfi_io_lock); 1628234429Sambrisko sx_xunlock(&sc->mfi_config_lock); 1629234429Sambrisko } 1630234429Sambrisko } 1631252643Smarkj if (sc->mfi_cam_rescan_cb != NULL && 1632252643Smarkj (detail->code == MR_EVT_PD_INSERTED || 1633252643Smarkj detail->code == MR_EVT_PD_REMOVED)) { 1634252643Smarkj sc->mfi_cam_rescan_cb(sc, detail->args.pd.device_id); 1635252643Smarkj } 1636234429Sambrisko break; 1637234429Sambrisko } 1638180038Sjhb} 1639180038Sjhb 1640234429Sambriskostatic void 1641234429Sambriskomfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) 1642234429Sambrisko{ 1643234429Sambrisko struct mfi_evt_queue_elm *elm; 1644234429Sambrisko 1645234429Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1646234429Sambrisko elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO); 1647234429Sambrisko if (elm == NULL) 1648234429Sambrisko return; 1649234429Sambrisko memcpy(&elm->detail, detail, sizeof(*detail)); 1650234429Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link); 1651234429Sambrisko taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task); 1652234429Sambrisko} 1653234429Sambrisko 1654234429Sambriskostatic void 1655234429Sambriskomfi_handle_evt(void *context, int pending) 1656234429Sambrisko{ 1657234429Sambrisko TAILQ_HEAD(,mfi_evt_queue_elm) queue; 1658234429Sambrisko struct mfi_softc *sc; 1659234429Sambrisko struct mfi_evt_queue_elm *elm; 1660234429Sambrisko 1661234429Sambrisko sc = context; 1662234429Sambrisko TAILQ_INIT(&queue); 1663234429Sambrisko mtx_lock(&sc->mfi_io_lock); 1664234429Sambrisko TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link); 1665234429Sambrisko mtx_unlock(&sc->mfi_io_lock); 1666234429Sambrisko while ((elm = TAILQ_FIRST(&queue)) != NULL) { 1667234429Sambrisko TAILQ_REMOVE(&queue, elm, link); 1668234429Sambrisko mfi_decode_evt(sc, &elm->detail); 1669234429Sambrisko free(elm, M_MFIBUF); 1670234429Sambrisko } 1671234429Sambrisko} 1672234429Sambrisko 1673157114Sscottlstatic int 1674158737Sambriskomfi_aen_register(struct mfi_softc *sc, int seq, int locale) 1675158737Sambrisko{ 1676158737Sambrisko struct mfi_command *cm; 1677158737Sambrisko struct mfi_dcmd_frame *dcmd; 1678158737Sambrisko union mfi_evt current_aen, prior_aen; 1679159806Sps struct mfi_evt_detail *ed = NULL; 1680163398Sscottl int error = 0; 1681158737Sambrisko 1682250496Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1683250496Ssmh 1684158737Sambrisko current_aen.word = locale; 1685158737Sambrisko if (sc->mfi_aen_cm != NULL) { 1686158737Sambrisko prior_aen.word = 1687158737Sambrisko ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1]; 1688222589Semaste if (prior_aen.members.evt_class <= current_aen.members.evt_class && 1689158737Sambrisko !((prior_aen.members.locale & current_aen.members.locale) 1690158737Sambrisko ^current_aen.members.locale)) { 1691158737Sambrisko return (0); 1692158737Sambrisko } else { 1693158737Sambrisko prior_aen.members.locale |= current_aen.members.locale; 1694222589Semaste if (prior_aen.members.evt_class 1695222589Semaste < current_aen.members.evt_class) 1696222589Semaste current_aen.members.evt_class = 1697222589Semaste prior_aen.members.evt_class; 1698243824Sdelphij mfi_abort(sc, &sc->mfi_aen_cm); 1699158737Sambrisko } 1700158737Sambrisko } 1701158737Sambrisko 1702159806Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT, 1703159806Sps (void **)&ed, sizeof(*ed)); 1704250496Ssmh if (error) 1705163398Sscottl goto out; 1706158737Sambrisko 1707158737Sambrisko dcmd = &cm->cm_frame->dcmd; 1708158737Sambrisko ((uint32_t *)&dcmd->mbox)[0] = seq; 1709158737Sambrisko ((uint32_t *)&dcmd->mbox)[1] = locale; 1710158737Sambrisko cm->cm_flags = MFI_CMD_DATAIN; 1711158737Sambrisko cm->cm_complete = mfi_aen_complete; 1712158737Sambrisko 1713234429Sambrisko sc->last_seq_num = seq; 1714158737Sambrisko sc->mfi_aen_cm = cm; 1715158737Sambrisko 1716158737Sambrisko mfi_enqueue_ready(cm); 1717158737Sambrisko mfi_startio(sc); 1718158737Sambrisko 1719163398Sscottlout: 1720163398Sscottl return (error); 1721158737Sambrisko} 1722158737Sambrisko 1723158737Sambriskostatic void 1724158737Sambriskomfi_aen_complete(struct mfi_command *cm) 1725158737Sambrisko{ 1726158737Sambrisko struct mfi_frame_header *hdr; 1727158737Sambrisko struct mfi_softc *sc; 1728158737Sambrisko struct mfi_evt_detail *detail; 1729163398Sscottl struct mfi_aen *mfi_aen_entry, *tmp; 1730158737Sambrisko int seq = 0, aborted = 0; 1731158737Sambrisko 1732158737Sambrisko sc = cm->cm_sc; 1733234429Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1734234429Sambrisko 1735158737Sambrisko if (sc->mfi_aen_cm == NULL) 1736158737Sambrisko return; 1737158737Sambrisko 1738250496Ssmh hdr = &cm->cm_frame->header; 1739250496Ssmh 1740235135Sambrisko if (sc->cm_aen_abort || 1741224039Sjhb hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 1742235135Sambrisko sc->cm_aen_abort = 0; 1743158737Sambrisko aborted = 1; 1744158737Sambrisko } else { 1745158737Sambrisko sc->mfi_aen_triggered = 1; 1746163398Sscottl if (sc->mfi_poll_waiting) { 1747163398Sscottl sc->mfi_poll_waiting = 0; 1748158737Sambrisko selwakeup(&sc->mfi_select); 1749163398Sscottl } 1750158737Sambrisko detail = cm->cm_data; 1751234429Sambrisko mfi_queue_evt(sc, detail); 1752158737Sambrisko seq = detail->seq + 1; 1753234429Sambrisko TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, 1754234429Sambrisko tmp) { 1755158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 1756158737Sambrisko aen_link); 1757163398Sscottl PROC_LOCK(mfi_aen_entry->p); 1758225617Skmacy kern_psignal(mfi_aen_entry->p, SIGIO); 1759163398Sscottl PROC_UNLOCK(mfi_aen_entry->p); 1760158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 1761158737Sambrisko } 1762158737Sambrisko } 1763158737Sambrisko 1764158737Sambrisko free(cm->cm_data, M_MFIBUF); 1765250496Ssmh wakeup(&sc->mfi_aen_cm); 1766158737Sambrisko sc->mfi_aen_cm = NULL; 1767158737Sambrisko mfi_release_command(cm); 1768158737Sambrisko 1769158737Sambrisko /* set it up again so the driver can catch more events */ 1770250496Ssmh if (!aborted) 1771158737Sambrisko mfi_aen_setup(sc, seq); 1772158737Sambrisko} 1773158737Sambrisko 1774180037Sjhb#define MAX_EVENTS 15 1775180037Sjhb 1776158737Sambriskostatic int 1777180037Sjhbmfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) 1778158737Sambrisko{ 1779158737Sambrisko struct mfi_command *cm; 1780158737Sambrisko struct mfi_dcmd_frame *dcmd; 1781162118Sambrisko struct mfi_evt_list *el; 1782180037Sjhb union mfi_evt class_locale; 1783180037Sjhb int error, i, seq, size; 1784158737Sambrisko 1785250496Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1786250496Ssmh 1787180037Sjhb class_locale.members.reserved = 0; 1788180037Sjhb class_locale.members.locale = mfi_event_locale; 1789222589Semaste class_locale.members.evt_class = mfi_event_class; 1790158737Sambrisko 1791162118Sambrisko size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) 1792162118Sambrisko * (MAX_EVENTS - 1); 1793162118Sambrisko el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO); 1794180037Sjhb if (el == NULL) 1795158737Sambrisko return (ENOMEM); 1796158737Sambrisko 1797180037Sjhb for (seq = start_seq;;) { 1798180037Sjhb if ((cm = mfi_dequeue_free(sc)) == NULL) { 1799180037Sjhb free(el, M_MFIBUF); 1800180037Sjhb return (EBUSY); 1801180037Sjhb } 1802158737Sambrisko 1803180037Sjhb dcmd = &cm->cm_frame->dcmd; 1804180037Sjhb bzero(dcmd->mbox, MFI_MBOX_SIZE); 1805180037Sjhb dcmd->header.cmd = MFI_CMD_DCMD; 1806180037Sjhb dcmd->header.timeout = 0; 1807180037Sjhb dcmd->header.data_len = size; 1808180037Sjhb dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET; 1809180037Sjhb ((uint32_t *)&dcmd->mbox)[0] = seq; 1810180037Sjhb ((uint32_t *)&dcmd->mbox)[1] = class_locale.word; 1811180037Sjhb cm->cm_sg = &dcmd->sgl; 1812180037Sjhb cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 1813180037Sjhb cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1814180037Sjhb cm->cm_data = el; 1815180037Sjhb cm->cm_len = size; 1816180037Sjhb 1817180037Sjhb if ((error = mfi_mapcmd(sc, cm)) != 0) { 1818180037Sjhb device_printf(sc->mfi_dev, 1819180037Sjhb "Failed to get controller entries\n"); 1820180037Sjhb mfi_release_command(cm); 1821180037Sjhb break; 1822180037Sjhb } 1823180037Sjhb 1824180037Sjhb bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1825180037Sjhb BUS_DMASYNC_POSTREAD); 1826180037Sjhb bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1827180037Sjhb 1828180037Sjhb if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) { 1829180037Sjhb mfi_release_command(cm); 1830180037Sjhb break; 1831180037Sjhb } 1832180037Sjhb if (dcmd->header.cmd_status != MFI_STAT_OK) { 1833180037Sjhb device_printf(sc->mfi_dev, 1834180037Sjhb "Error %d fetching controller entries\n", 1835180037Sjhb dcmd->header.cmd_status); 1836180037Sjhb mfi_release_command(cm); 1837250496Ssmh error = EIO; 1838180037Sjhb break; 1839180037Sjhb } 1840158737Sambrisko mfi_release_command(cm); 1841158737Sambrisko 1842162473Sambrisko for (i = 0; i < el->count; i++) { 1843180037Sjhb /* 1844180037Sjhb * If this event is newer than 'stop_seq' then 1845180037Sjhb * break out of the loop. Note that the log 1846180037Sjhb * is a circular buffer so we have to handle 1847180037Sjhb * the case that our stop point is earlier in 1848180037Sjhb * the buffer than our start point. 1849180037Sjhb */ 1850180037Sjhb if (el->event[i].seq >= stop_seq) { 1851180037Sjhb if (start_seq <= stop_seq) 1852180037Sjhb break; 1853180037Sjhb else if (el->event[i].seq < start_seq) 1854180037Sjhb break; 1855180037Sjhb } 1856234429Sambrisko mfi_queue_evt(sc, &el->event[i]); 1857162473Sambrisko } 1858180037Sjhb seq = el->event[el->count - 1].seq + 1; 1859162118Sambrisko } 1860158737Sambrisko 1861180037Sjhb free(el, M_MFIBUF); 1862250496Ssmh return (error); 1863158737Sambrisko} 1864158737Sambrisko 1865158737Sambriskostatic int 1866159811Spsmfi_add_ld(struct mfi_softc *sc, int id) 1867157114Sscottl{ 1868157114Sscottl struct mfi_command *cm; 1869159811Sps struct mfi_dcmd_frame *dcmd = NULL; 1870159811Sps struct mfi_ld_info *ld_info = NULL; 1871243824Sdelphij struct mfi_disk_pending *ld_pend; 1872159811Sps int error; 1873157114Sscottl 1874159811Sps mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1875159811Sps 1876243824Sdelphij ld_pend = malloc(sizeof(*ld_pend), M_MFIBUF, M_NOWAIT | M_ZERO); 1877243824Sdelphij if (ld_pend != NULL) { 1878243824Sdelphij ld_pend->ld_id = id; 1879243824Sdelphij TAILQ_INSERT_TAIL(&sc->mfi_ld_pend_tqh, ld_pend, ld_link); 1880243824Sdelphij } 1881243824Sdelphij 1882159811Sps error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO, 1883159811Sps (void **)&ld_info, sizeof(*ld_info)); 1884159811Sps if (error) { 1885159811Sps device_printf(sc->mfi_dev, 1886159811Sps "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error); 1887159811Sps if (ld_info) 1888159811Sps free(ld_info, M_MFIBUF); 1889159811Sps return (error); 1890157624Sscottl } 1891159811Sps cm->cm_flags = MFI_CMD_DATAIN; 1892159811Sps dcmd = &cm->cm_frame->dcmd; 1893159811Sps dcmd->mbox[0] = id; 1894160052Sambrisko if (mfi_wait_command(sc, cm) != 0) { 1895160052Sambrisko device_printf(sc->mfi_dev, 1896160052Sambrisko "Failed to get logical drive: %d\n", id); 1897160052Sambrisko free(ld_info, M_MFIBUF); 1898160052Sambrisko return (0); 1899160052Sambrisko } 1900234429Sambrisko if (ld_info->ld_config.params.isSSCD != 1) 1901234429Sambrisko mfi_add_ld_complete(cm); 1902234429Sambrisko else { 1903234429Sambrisko mfi_release_command(cm); 1904234429Sambrisko if (ld_info) /* SSCD drives ld_info free here */ 1905234429Sambrisko free(ld_info, M_MFIBUF); 1906234429Sambrisko } 1907157114Sscottl return (0); 1908157114Sscottl} 1909157114Sscottl 1910157114Sscottlstatic void 1911159811Spsmfi_add_ld_complete(struct mfi_command *cm) 1912157114Sscottl{ 1913157114Sscottl struct mfi_frame_header *hdr; 1914159811Sps struct mfi_ld_info *ld_info; 1915157114Sscottl struct mfi_softc *sc; 1916159811Sps device_t child; 1917157114Sscottl 1918157114Sscottl sc = cm->cm_sc; 1919157114Sscottl hdr = &cm->cm_frame->header; 1920159811Sps ld_info = cm->cm_private; 1921157114Sscottl 1922243824Sdelphij if (sc->cm_map_abort || hdr->cmd_status != MFI_STAT_OK) { 1923159811Sps free(ld_info, M_MFIBUF); 1924243824Sdelphij wakeup(&sc->mfi_map_sync_cm); 1925157114Sscottl mfi_release_command(cm); 1926157114Sscottl return; 1927157114Sscottl } 1928243824Sdelphij wakeup(&sc->mfi_map_sync_cm); 1929157114Sscottl mfi_release_command(cm); 1930157114Sscottl 1931169611Sscottl mtx_unlock(&sc->mfi_io_lock); 1932196403Sjhb mtx_lock(&Giant); 1933157114Sscottl if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) { 1934157114Sscottl device_printf(sc->mfi_dev, "Failed to add logical disk\n"); 1935159811Sps free(ld_info, M_MFIBUF); 1936196403Sjhb mtx_unlock(&Giant); 1937169611Sscottl mtx_lock(&sc->mfi_io_lock); 1938159811Sps return; 1939157114Sscottl } 1940157114Sscottl 1941169451Sscottl device_set_ivars(child, ld_info); 1942157114Sscottl device_set_desc(child, "MFI Logical Disk"); 1943157114Sscottl bus_generic_attach(sc->mfi_dev); 1944196403Sjhb mtx_unlock(&Giant); 1945157114Sscottl mtx_lock(&sc->mfi_io_lock); 1946157114Sscottl} 1947163399Sscottl 1948234429Sambriskostatic int mfi_add_sys_pd(struct mfi_softc *sc, int id) 1949234429Sambrisko{ 1950234429Sambrisko struct mfi_command *cm; 1951234429Sambrisko struct mfi_dcmd_frame *dcmd = NULL; 1952234429Sambrisko struct mfi_pd_info *pd_info = NULL; 1953243824Sdelphij struct mfi_system_pending *syspd_pend; 1954234429Sambrisko int error; 1955234429Sambrisko 1956234429Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1957234429Sambrisko 1958243824Sdelphij syspd_pend = malloc(sizeof(*syspd_pend), M_MFIBUF, M_NOWAIT | M_ZERO); 1959243824Sdelphij if (syspd_pend != NULL) { 1960243824Sdelphij syspd_pend->pd_id = id; 1961243824Sdelphij TAILQ_INSERT_TAIL(&sc->mfi_syspd_pend_tqh, syspd_pend, pd_link); 1962243824Sdelphij } 1963243824Sdelphij 1964234429Sambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO, 1965234429Sambrisko (void **)&pd_info, sizeof(*pd_info)); 1966234429Sambrisko if (error) { 1967234429Sambrisko device_printf(sc->mfi_dev, 1968234429Sambrisko "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n", 1969234429Sambrisko error); 1970234429Sambrisko if (pd_info) 1971234429Sambrisko free(pd_info, M_MFIBUF); 1972234429Sambrisko return (error); 1973234429Sambrisko } 1974234429Sambrisko cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1975234429Sambrisko dcmd = &cm->cm_frame->dcmd; 1976234429Sambrisko dcmd->mbox[0]=id; 1977234429Sambrisko dcmd->header.scsi_status = 0; 1978234429Sambrisko dcmd->header.pad0 = 0; 1979250496Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) { 1980234429Sambrisko device_printf(sc->mfi_dev, 1981234429Sambrisko "Failed to get physical drive info %d\n", id); 1982234429Sambrisko free(pd_info, M_MFIBUF); 1983250496Ssmh mfi_release_command(cm); 1984250496Ssmh return (error); 1985234429Sambrisko } 1986234429Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1987234429Sambrisko BUS_DMASYNC_POSTREAD); 1988234429Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1989234429Sambrisko mfi_add_sys_pd_complete(cm); 1990234429Sambrisko return (0); 1991234429Sambrisko} 1992234429Sambrisko 1993234429Sambriskostatic void 1994234429Sambriskomfi_add_sys_pd_complete(struct mfi_command *cm) 1995234429Sambrisko{ 1996234429Sambrisko struct mfi_frame_header *hdr; 1997234429Sambrisko struct mfi_pd_info *pd_info; 1998234429Sambrisko struct mfi_softc *sc; 1999234429Sambrisko device_t child; 2000234429Sambrisko 2001234429Sambrisko sc = cm->cm_sc; 2002234429Sambrisko hdr = &cm->cm_frame->header; 2003234429Sambrisko pd_info = cm->cm_private; 2004234429Sambrisko 2005234429Sambrisko if (hdr->cmd_status != MFI_STAT_OK) { 2006234429Sambrisko free(pd_info, M_MFIBUF); 2007234429Sambrisko mfi_release_command(cm); 2008234429Sambrisko return; 2009234429Sambrisko } 2010234429Sambrisko if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) { 2011234429Sambrisko device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n", 2012234429Sambrisko pd_info->ref.v.device_id); 2013234429Sambrisko free(pd_info, M_MFIBUF); 2014234429Sambrisko mfi_release_command(cm); 2015234429Sambrisko return; 2016234429Sambrisko } 2017234429Sambrisko mfi_release_command(cm); 2018234429Sambrisko 2019234429Sambrisko mtx_unlock(&sc->mfi_io_lock); 2020234429Sambrisko mtx_lock(&Giant); 2021234429Sambrisko if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) { 2022234429Sambrisko device_printf(sc->mfi_dev, "Failed to add system pd\n"); 2023234429Sambrisko free(pd_info, M_MFIBUF); 2024234429Sambrisko mtx_unlock(&Giant); 2025234429Sambrisko mtx_lock(&sc->mfi_io_lock); 2026234429Sambrisko return; 2027234429Sambrisko } 2028234429Sambrisko 2029234429Sambrisko device_set_ivars(child, pd_info); 2030234429Sambrisko device_set_desc(child, "MFI System PD"); 2031234429Sambrisko bus_generic_attach(sc->mfi_dev); 2032234429Sambrisko mtx_unlock(&Giant); 2033234429Sambrisko mtx_lock(&sc->mfi_io_lock); 2034234429Sambrisko} 2035235135Sambrisko 2036157114Sscottlstatic struct mfi_command * 2037157114Sscottlmfi_bio_command(struct mfi_softc *sc) 2038157114Sscottl{ 2039157114Sscottl struct bio *bio; 2040234429Sambrisko struct mfi_command *cm = NULL; 2041157114Sscottl 2042234429Sambrisko /*reserving two commands to avoid starvation for IOCTL*/ 2043235135Sambrisko if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) { 2044157114Sscottl return (NULL); 2045234429Sambrisko } 2046157114Sscottl if ((bio = mfi_dequeue_bio(sc)) == NULL) { 2047157114Sscottl return (NULL); 2048157114Sscottl } 2049234429Sambrisko if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) { 2050234429Sambrisko cm = mfi_build_ldio(sc, bio); 2051234429Sambrisko } else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) { 2052234429Sambrisko cm = mfi_build_syspdio(sc, bio); 2053234429Sambrisko } 2054234429Sambrisko if (!cm) 2055234429Sambrisko mfi_enqueue_bio(sc, bio); 2056234429Sambrisko return cm; 2057234429Sambrisko} 2058243823Sdelphij 2059243824Sdelphij/* 2060243824Sdelphij * mostly copied from cam/scsi/scsi_all.c:scsi_read_write 2061243824Sdelphij */ 2062243824Sdelphij 2063243824Sdelphijint 2064243824Sdelphijmfi_build_cdb(int readop, uint8_t byte2, u_int64_t lba, u_int32_t block_count, uint8_t *cdb) 2065243823Sdelphij{ 2066243823Sdelphij int cdb_len; 2067243823Sdelphij 2068243823Sdelphij if (((lba & 0x1fffff) == lba) 2069243823Sdelphij && ((block_count & 0xff) == block_count) 2070243823Sdelphij && (byte2 == 0)) { 2071243823Sdelphij /* We can fit in a 6 byte cdb */ 2072243823Sdelphij struct scsi_rw_6 *scsi_cmd; 2073243823Sdelphij 2074243824Sdelphij scsi_cmd = (struct scsi_rw_6 *)cdb; 2075243823Sdelphij scsi_cmd->opcode = readop ? READ_6 : WRITE_6; 2076243823Sdelphij scsi_ulto3b(lba, scsi_cmd->addr); 2077243823Sdelphij scsi_cmd->length = block_count & 0xff; 2078243823Sdelphij scsi_cmd->control = 0; 2079243823Sdelphij cdb_len = sizeof(*scsi_cmd); 2080243823Sdelphij } else if (((block_count & 0xffff) == block_count) && ((lba & 0xffffffff) == lba)) { 2081243823Sdelphij /* Need a 10 byte CDB */ 2082243823Sdelphij struct scsi_rw_10 *scsi_cmd; 2083243823Sdelphij 2084243824Sdelphij scsi_cmd = (struct scsi_rw_10 *)cdb; 2085243823Sdelphij scsi_cmd->opcode = readop ? READ_10 : WRITE_10; 2086243823Sdelphij scsi_cmd->byte2 = byte2; 2087243823Sdelphij scsi_ulto4b(lba, scsi_cmd->addr); 2088243823Sdelphij scsi_cmd->reserved = 0; 2089243823Sdelphij scsi_ulto2b(block_count, scsi_cmd->length); 2090243823Sdelphij scsi_cmd->control = 0; 2091243823Sdelphij cdb_len = sizeof(*scsi_cmd); 2092243823Sdelphij } else if (((block_count & 0xffffffff) == block_count) && 2093243823Sdelphij ((lba & 0xffffffff) == lba)) { 2094243823Sdelphij /* Block count is too big for 10 byte CDB use a 12 byte CDB */ 2095243823Sdelphij struct scsi_rw_12 *scsi_cmd; 2096243823Sdelphij 2097243824Sdelphij scsi_cmd = (struct scsi_rw_12 *)cdb; 2098243823Sdelphij scsi_cmd->opcode = readop ? READ_12 : WRITE_12; 2099243823Sdelphij scsi_cmd->byte2 = byte2; 2100243823Sdelphij scsi_ulto4b(lba, scsi_cmd->addr); 2101243823Sdelphij scsi_cmd->reserved = 0; 2102243823Sdelphij scsi_ulto4b(block_count, scsi_cmd->length); 2103243823Sdelphij scsi_cmd->control = 0; 2104243823Sdelphij cdb_len = sizeof(*scsi_cmd); 2105243823Sdelphij } else { 2106243823Sdelphij /* 2107243823Sdelphij * 16 byte CDB. We'll only get here if the LBA is larger 2108243823Sdelphij * than 2^32 2109243823Sdelphij */ 2110243823Sdelphij struct scsi_rw_16 *scsi_cmd; 2111243823Sdelphij 2112243824Sdelphij scsi_cmd = (struct scsi_rw_16 *)cdb; 2113243823Sdelphij scsi_cmd->opcode = readop ? READ_16 : WRITE_16; 2114243823Sdelphij scsi_cmd->byte2 = byte2; 2115243823Sdelphij scsi_u64to8b(lba, scsi_cmd->addr); 2116243823Sdelphij scsi_cmd->reserved = 0; 2117243823Sdelphij scsi_ulto4b(block_count, scsi_cmd->length); 2118243823Sdelphij scsi_cmd->control = 0; 2119243823Sdelphij cdb_len = sizeof(*scsi_cmd); 2120243823Sdelphij } 2121243823Sdelphij 2122243823Sdelphij return cdb_len; 2123243823Sdelphij} 2124243823Sdelphij 2125234429Sambriskostatic struct mfi_command * 2126234429Sambriskomfi_build_syspdio(struct mfi_softc *sc, struct bio *bio) 2127234429Sambrisko{ 2128234429Sambrisko struct mfi_command *cm; 2129234429Sambrisko struct mfi_pass_frame *pass; 2130243824Sdelphij uint32_t context = 0; 2131243824Sdelphij int flags = 0, blkcount = 0, readop; 2132243823Sdelphij uint8_t cdb_len; 2133157114Sscottl 2134250496Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2135250496Ssmh 2136234429Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 2137234429Sambrisko return (NULL); 2138234429Sambrisko 2139234429Sambrisko /* Zero out the MFI frame */ 2140243824Sdelphij context = cm->cm_frame->header.context; 2141234429Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2142234429Sambrisko cm->cm_frame->header.context = context; 2143234429Sambrisko pass = &cm->cm_frame->pass; 2144234429Sambrisko bzero(pass->cdb, 16); 2145234429Sambrisko pass->header.cmd = MFI_CMD_PD_SCSI_IO; 2146234429Sambrisko switch (bio->bio_cmd & 0x03) { 2147234429Sambrisko case BIO_READ: 2148234429Sambrisko flags = MFI_CMD_DATAIN; 2149243824Sdelphij readop = 1; 2150234429Sambrisko break; 2151234429Sambrisko case BIO_WRITE: 2152234429Sambrisko flags = MFI_CMD_DATAOUT; 2153243824Sdelphij readop = 0; 2154234429Sambrisko break; 2155234429Sambrisko default: 2156243823Sdelphij /* TODO: what about BIO_DELETE??? */ 2157243824Sdelphij panic("Unsupported bio command %x\n", bio->bio_cmd); 2158234429Sambrisko } 2159234429Sambrisko 2160234429Sambrisko /* Cheat with the sector length to avoid a non-constant division */ 2161243824Sdelphij blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2162234429Sambrisko /* Fill the LBA and Transfer length in CDB */ 2163243824Sdelphij cdb_len = mfi_build_cdb(readop, 0, bio->bio_pblkno, blkcount, 2164243824Sdelphij pass->cdb); 2165234429Sambrisko pass->header.target_id = (uintptr_t)bio->bio_driver1; 2166243824Sdelphij pass->header.lun_id = 0; 2167234429Sambrisko pass->header.timeout = 0; 2168234429Sambrisko pass->header.flags = 0; 2169234429Sambrisko pass->header.scsi_status = 0; 2170234429Sambrisko pass->header.sense_len = MFI_SENSE_LEN; 2171234429Sambrisko pass->header.data_len = bio->bio_bcount; 2172243823Sdelphij pass->header.cdb_len = cdb_len; 2173234429Sambrisko pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2174234429Sambrisko pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2175234429Sambrisko cm->cm_complete = mfi_bio_complete; 2176234429Sambrisko cm->cm_private = bio; 2177234429Sambrisko cm->cm_data = bio->bio_data; 2178234429Sambrisko cm->cm_len = bio->bio_bcount; 2179234429Sambrisko cm->cm_sg = &pass->sgl; 2180234429Sambrisko cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; 2181234429Sambrisko cm->cm_flags = flags; 2182250496Ssmh 2183234429Sambrisko return (cm); 2184234429Sambrisko} 2185234429Sambrisko 2186234429Sambriskostatic struct mfi_command * 2187234429Sambriskomfi_build_ldio(struct mfi_softc *sc, struct bio *bio) 2188234429Sambrisko{ 2189234429Sambrisko struct mfi_io_frame *io; 2190234429Sambrisko struct mfi_command *cm; 2191243823Sdelphij int flags; 2192243823Sdelphij uint32_t blkcount; 2193234429Sambrisko uint32_t context = 0; 2194234429Sambrisko 2195250496Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2196250496Ssmh 2197234429Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 2198234429Sambrisko return (NULL); 2199234429Sambrisko 2200234429Sambrisko /* Zero out the MFI frame */ 2201234429Sambrisko context = cm->cm_frame->header.context; 2202234429Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2203234429Sambrisko cm->cm_frame->header.context = context; 2204157114Sscottl io = &cm->cm_frame->io; 2205157114Sscottl switch (bio->bio_cmd & 0x03) { 2206157114Sscottl case BIO_READ: 2207157114Sscottl io->header.cmd = MFI_CMD_LD_READ; 2208157114Sscottl flags = MFI_CMD_DATAIN; 2209157114Sscottl break; 2210157114Sscottl case BIO_WRITE: 2211157114Sscottl io->header.cmd = MFI_CMD_LD_WRITE; 2212157114Sscottl flags = MFI_CMD_DATAOUT; 2213157114Sscottl break; 2214157114Sscottl default: 2215243823Sdelphij /* TODO: what about BIO_DELETE??? */ 2216243824Sdelphij panic("Unsupported bio command %x\n", bio->bio_cmd); 2217157114Sscottl } 2218157114Sscottl 2219157114Sscottl /* Cheat with the sector length to avoid a non-constant division */ 2220157114Sscottl blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2221157114Sscottl io->header.target_id = (uintptr_t)bio->bio_driver1; 2222157114Sscottl io->header.timeout = 0; 2223157114Sscottl io->header.flags = 0; 2224234429Sambrisko io->header.scsi_status = 0; 2225157114Sscottl io->header.sense_len = MFI_SENSE_LEN; 2226157114Sscottl io->header.data_len = blkcount; 2227234429Sambrisko io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2228234429Sambrisko io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2229157114Sscottl io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32; 2230157114Sscottl io->lba_lo = bio->bio_pblkno & 0xffffffff; 2231157114Sscottl cm->cm_complete = mfi_bio_complete; 2232157114Sscottl cm->cm_private = bio; 2233157114Sscottl cm->cm_data = bio->bio_data; 2234157114Sscottl cm->cm_len = bio->bio_bcount; 2235157114Sscottl cm->cm_sg = &io->sgl; 2236157114Sscottl cm->cm_total_frame_size = MFI_IO_FRAME_SIZE; 2237157114Sscottl cm->cm_flags = flags; 2238250496Ssmh 2239157114Sscottl return (cm); 2240157114Sscottl} 2241157114Sscottl 2242157114Sscottlstatic void 2243157114Sscottlmfi_bio_complete(struct mfi_command *cm) 2244157114Sscottl{ 2245157114Sscottl struct bio *bio; 2246157114Sscottl struct mfi_frame_header *hdr; 2247157114Sscottl struct mfi_softc *sc; 2248157114Sscottl 2249157114Sscottl bio = cm->cm_private; 2250157114Sscottl hdr = &cm->cm_frame->header; 2251157114Sscottl sc = cm->cm_sc; 2252157114Sscottl 2253224039Sjhb if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) { 2254157114Sscottl bio->bio_flags |= BIO_ERROR; 2255157114Sscottl bio->bio_error = EIO; 2256250496Ssmh device_printf(sc->mfi_dev, "I/O error, cmd=%p, status=%#x, " 2257250496Ssmh "scsi_status=%#x\n", cm, hdr->cmd_status, hdr->scsi_status); 2258157114Sscottl mfi_print_sense(cm->cm_sc, cm->cm_sense); 2259184897Sambrisko } else if (cm->cm_error != 0) { 2260184897Sambrisko bio->bio_flags |= BIO_ERROR; 2261250496Ssmh bio->bio_error = cm->cm_error; 2262250496Ssmh device_printf(sc->mfi_dev, "I/O error, cmd=%p, error=%#x\n", 2263250496Ssmh cm, cm->cm_error); 2264157114Sscottl } 2265157114Sscottl 2266157114Sscottl mfi_release_command(cm); 2267157114Sscottl mfi_disk_complete(bio); 2268157114Sscottl} 2269157114Sscottl 2270157114Sscottlvoid 2271157114Sscottlmfi_startio(struct mfi_softc *sc) 2272157114Sscottl{ 2273157114Sscottl struct mfi_command *cm; 2274169611Sscottl struct ccb_hdr *ccbh; 2275157114Sscottl 2276157114Sscottl for (;;) { 2277157114Sscottl /* Don't bother if we're short on resources */ 2278157114Sscottl if (sc->mfi_flags & MFI_FLAGS_QFRZN) 2279157114Sscottl break; 2280157114Sscottl 2281157114Sscottl /* Try a command that has already been prepared */ 2282157114Sscottl cm = mfi_dequeue_ready(sc); 2283157114Sscottl 2284169611Sscottl if (cm == NULL) { 2285169611Sscottl if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL) 2286169611Sscottl cm = sc->mfi_cam_start(ccbh); 2287169611Sscottl } 2288169611Sscottl 2289157114Sscottl /* Nope, so look for work on the bioq */ 2290157114Sscottl if (cm == NULL) 2291157114Sscottl cm = mfi_bio_command(sc); 2292157114Sscottl 2293157114Sscottl /* No work available, so exit */ 2294157114Sscottl if (cm == NULL) 2295157114Sscottl break; 2296157114Sscottl 2297157114Sscottl /* Send the command to the controller */ 2298157114Sscottl if (mfi_mapcmd(sc, cm) != 0) { 2299250496Ssmh device_printf(sc->mfi_dev, "Failed to startio\n"); 2300157114Sscottl mfi_requeue_ready(cm); 2301157114Sscottl break; 2302157114Sscottl } 2303157114Sscottl } 2304157114Sscottl} 2305157114Sscottl 2306234429Sambriskoint 2307157114Sscottlmfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm) 2308157114Sscottl{ 2309157114Sscottl int error, polled; 2310157114Sscottl 2311163398Sscottl mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2312163398Sscottl 2313234429Sambrisko if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) { 2314157114Sscottl polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0; 2315251874Sscottl if (cm->cm_flags & MFI_CMD_CCB) 2316251874Sscottl error = bus_dmamap_load_ccb(sc->mfi_buffer_dmat, 2317251874Sscottl cm->cm_dmamap, cm->cm_data, mfi_data_cb, cm, 2318251874Sscottl polled); 2319251874Sscottl else 2320251874Sscottl error = bus_dmamap_load(sc->mfi_buffer_dmat, 2321251874Sscottl cm->cm_dmamap, cm->cm_data, cm->cm_len, 2322251874Sscottl mfi_data_cb, cm, polled); 2323157114Sscottl if (error == EINPROGRESS) { 2324157114Sscottl sc->mfi_flags |= MFI_FLAGS_QFRZN; 2325157114Sscottl return (0); 2326157114Sscottl } 2327157114Sscottl } else { 2328250496Ssmh error = mfi_send_frame(sc, cm); 2329157114Sscottl } 2330157114Sscottl 2331157114Sscottl return (error); 2332157114Sscottl} 2333157114Sscottl 2334157114Sscottlstatic void 2335157114Sscottlmfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 2336157114Sscottl{ 2337157114Sscottl struct mfi_frame_header *hdr; 2338157114Sscottl struct mfi_command *cm; 2339157237Sscottl union mfi_sgl *sgl; 2340157114Sscottl struct mfi_softc *sc; 2341225918Smav int i, j, first, dir; 2342250496Ssmh int sge_size, locked; 2343157114Sscottl 2344157114Sscottl cm = (struct mfi_command *)arg; 2345157114Sscottl sc = cm->cm_sc; 2346157237Sscottl hdr = &cm->cm_frame->header; 2347157237Sscottl sgl = cm->cm_sg; 2348157114Sscottl 2349250496Ssmh /* 2350250496Ssmh * We need to check if we have the lock as this is async 2351250496Ssmh * callback so even though our caller mfi_mapcmd asserts 2352250496Ssmh * it has the lock, there is no garantee that hasn't been 2353250496Ssmh * dropped if bus_dmamap_load returned prior to our 2354250496Ssmh * completion. 2355250496Ssmh */ 2356250496Ssmh if ((locked = mtx_owned(&sc->mfi_io_lock)) == 0) 2357250496Ssmh mtx_lock(&sc->mfi_io_lock); 2358250496Ssmh 2359170284Sambrisko if (error) { 2360170284Sambrisko printf("error %d in callback\n", error); 2361170284Sambrisko cm->cm_error = error; 2362170284Sambrisko mfi_complete(sc, cm); 2363250496Ssmh goto out; 2364170284Sambrisko } 2365234429Sambrisko /* Use IEEE sgl only for IO's on a SKINNY controller 2366234429Sambrisko * For other commands on a SKINNY controller use either 2367234429Sambrisko * sg32 or sg64 based on the sizeof(bus_addr_t). 2368234429Sambrisko * Also calculate the total frame size based on the type 2369234429Sambrisko * of SGL used. 2370234429Sambrisko */ 2371234429Sambrisko if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) || 2372234429Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) || 2373234429Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) && 2374234429Sambrisko (sc->mfi_flags & MFI_FLAGS_SKINNY)) { 2375157237Sscottl for (i = 0; i < nsegs; i++) { 2376234429Sambrisko sgl->sg_skinny[i].addr = segs[i].ds_addr; 2377234429Sambrisko sgl->sg_skinny[i].len = segs[i].ds_len; 2378234429Sambrisko sgl->sg_skinny[i].flag = 0; 2379157114Sscottl } 2380234429Sambrisko hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64; 2381234429Sambrisko sge_size = sizeof(struct mfi_sg_skinny); 2382234429Sambrisko hdr->sg_count = nsegs; 2383157237Sscottl } else { 2384234429Sambrisko j = 0; 2385234429Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 2386234429Sambrisko first = cm->cm_stp_len; 2387234429Sambrisko if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { 2388234429Sambrisko sgl->sg32[j].addr = segs[0].ds_addr; 2389234429Sambrisko sgl->sg32[j++].len = first; 2390234429Sambrisko } else { 2391234429Sambrisko sgl->sg64[j].addr = segs[0].ds_addr; 2392234429Sambrisko sgl->sg64[j++].len = first; 2393234429Sambrisko } 2394234429Sambrisko } else 2395225918Smav first = 0; 2396234429Sambrisko if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { 2397234429Sambrisko for (i = 0; i < nsegs; i++) { 2398234429Sambrisko sgl->sg32[j].addr = segs[i].ds_addr + first; 2399234429Sambrisko sgl->sg32[j++].len = segs[i].ds_len - first; 2400234429Sambrisko first = 0; 2401234429Sambrisko } 2402234429Sambrisko } else { 2403234429Sambrisko for (i = 0; i < nsegs; i++) { 2404234429Sambrisko sgl->sg64[j].addr = segs[i].ds_addr + first; 2405234429Sambrisko sgl->sg64[j++].len = segs[i].ds_len - first; 2406234429Sambrisko first = 0; 2407234429Sambrisko } 2408234429Sambrisko hdr->flags |= MFI_FRAME_SGL64; 2409157237Sscottl } 2410234429Sambrisko hdr->sg_count = j; 2411234429Sambrisko sge_size = sc->mfi_sge_size; 2412157114Sscottl } 2413157114Sscottl 2414157114Sscottl dir = 0; 2415157114Sscottl if (cm->cm_flags & MFI_CMD_DATAIN) { 2416157114Sscottl dir |= BUS_DMASYNC_PREREAD; 2417157114Sscottl hdr->flags |= MFI_FRAME_DIR_READ; 2418157114Sscottl } 2419157114Sscottl if (cm->cm_flags & MFI_CMD_DATAOUT) { 2420157114Sscottl dir |= BUS_DMASYNC_PREWRITE; 2421157114Sscottl hdr->flags |= MFI_FRAME_DIR_WRITE; 2422157114Sscottl } 2423157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir); 2424157114Sscottl cm->cm_flags |= MFI_CMD_MAPPED; 2425157114Sscottl 2426157114Sscottl /* 2427157114Sscottl * Instead of calculating the total number of frames in the 2428157114Sscottl * compound frame, it's already assumed that there will be at 2429157114Sscottl * least 1 frame, so don't compensate for the modulo of the 2430157114Sscottl * following division. 2431157114Sscottl */ 2432162458Sscottl cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs); 2433157114Sscottl cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; 2434157114Sscottl 2435250496Ssmh if ((error = mfi_send_frame(sc, cm)) != 0) { 2436250496Ssmh printf("error %d in callback from mfi_send_frame\n", error); 2437250496Ssmh cm->cm_error = error; 2438250496Ssmh mfi_complete(sc, cm); 2439250496Ssmh goto out; 2440250496Ssmh } 2441157114Sscottl 2442250496Ssmhout: 2443250496Ssmh /* leave the lock in the state we found it */ 2444250496Ssmh if (locked == 0) 2445250496Ssmh mtx_unlock(&sc->mfi_io_lock); 2446250496Ssmh 2447157114Sscottl return; 2448157114Sscottl} 2449157114Sscottl 2450157114Sscottlstatic int 2451157114Sscottlmfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm) 2452157114Sscottl{ 2453250496Ssmh int error; 2454250496Ssmh 2455250496Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2456250496Ssmh 2457250496Ssmh if (sc->MFA_enabled) 2458250496Ssmh error = mfi_tbolt_send_frame(sc, cm); 2459250496Ssmh else 2460250496Ssmh error = mfi_std_send_frame(sc, cm); 2461250496Ssmh 2462250496Ssmh if (error != 0 && (cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0) 2463250496Ssmh mfi_remove_busy(cm); 2464250496Ssmh 2465250496Ssmh return (error); 2466250496Ssmh} 2467250496Ssmh 2468250496Ssmhstatic int 2469250496Ssmhmfi_std_send_frame(struct mfi_softc *sc, struct mfi_command *cm) 2470250496Ssmh{ 2471164375Sscottl struct mfi_frame_header *hdr; 2472250496Ssmh int tm = mfi_polled_cmd_timeout * 1000; 2473157114Sscottl 2474164375Sscottl hdr = &cm->cm_frame->header; 2475164375Sscottl 2476164375Sscottl if ((cm->cm_flags & MFI_CMD_POLLED) == 0) { 2477164375Sscottl cm->cm_timestamp = time_uptime; 2478164375Sscottl mfi_enqueue_busy(cm); 2479164375Sscottl } else { 2480224039Sjhb hdr->cmd_status = MFI_STAT_INVALID_STATUS; 2481164375Sscottl hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 2482164375Sscottl } 2483164375Sscottl 2484157114Sscottl /* 2485157114Sscottl * The bus address of the command is aligned on a 64 byte boundary, 2486157114Sscottl * leaving the least 6 bits as zero. For whatever reason, the 2487157114Sscottl * hardware wants the address shifted right by three, leaving just 2488162458Sscottl * 3 zero bits. These three bits are then used as a prefetching 2489162458Sscottl * hint for the hardware to predict how many frames need to be 2490162458Sscottl * fetched across the bus. If a command has more than 8 frames 2491162458Sscottl * then the 3 bits are set to 0x7 and the firmware uses other 2492162458Sscottl * information in the command to determine the total amount to fetch. 2493162458Sscottl * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames 2494162458Sscottl * is enough for both 32bit and 64bit systems. 2495157114Sscottl */ 2496162458Sscottl if (cm->cm_extra_frames > 7) 2497162458Sscottl cm->cm_extra_frames = 7; 2498162458Sscottl 2499234429Sambrisko sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames); 2500164375Sscottl 2501164375Sscottl if ((cm->cm_flags & MFI_CMD_POLLED) == 0) 2502164375Sscottl return (0); 2503164375Sscottl 2504164375Sscottl /* This is a polled command, so busy-wait for it to complete. */ 2505224039Sjhb while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 2506164375Sscottl DELAY(1000); 2507165225Sambrisko tm -= 1; 2508164375Sscottl if (tm <= 0) 2509164375Sscottl break; 2510164375Sscottl } 2511164375Sscottl 2512224039Sjhb if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 2513165225Sambrisko device_printf(sc->mfi_dev, "Frame %p timed out " 2514234429Sambrisko "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode); 2515164375Sscottl return (ETIMEDOUT); 2516164375Sscottl } 2517164375Sscottl 2518157114Sscottl return (0); 2519157114Sscottl} 2520157114Sscottl 2521234429Sambrisko 2522234429Sambriskovoid 2523157114Sscottlmfi_complete(struct mfi_softc *sc, struct mfi_command *cm) 2524157114Sscottl{ 2525157114Sscottl int dir; 2526250496Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2527157114Sscottl 2528157114Sscottl if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) { 2529157114Sscottl dir = 0; 2530225918Smav if ((cm->cm_flags & MFI_CMD_DATAIN) || 2531225918Smav (cm->cm_frame->header.cmd == MFI_CMD_STP)) 2532157114Sscottl dir |= BUS_DMASYNC_POSTREAD; 2533157114Sscottl if (cm->cm_flags & MFI_CMD_DATAOUT) 2534157114Sscottl dir |= BUS_DMASYNC_POSTWRITE; 2535157114Sscottl 2536157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir); 2537157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2538157114Sscottl cm->cm_flags &= ~MFI_CMD_MAPPED; 2539157114Sscottl } 2540157114Sscottl 2541170284Sambrisko cm->cm_flags |= MFI_CMD_COMPLETED; 2542170284Sambrisko 2543157114Sscottl if (cm->cm_complete != NULL) 2544157114Sscottl cm->cm_complete(cm); 2545159811Sps else 2546159811Sps wakeup(cm); 2547157114Sscottl} 2548157114Sscottl 2549158737Sambriskostatic int 2550243824Sdelphijmfi_abort(struct mfi_softc *sc, struct mfi_command **cm_abort) 2551158737Sambrisko{ 2552158737Sambrisko struct mfi_command *cm; 2553158737Sambrisko struct mfi_abort_frame *abort; 2554250496Ssmh int i = 0, error; 2555234429Sambrisko uint32_t context = 0; 2556158737Sambrisko 2557243824Sdelphij mtx_lock(&sc->mfi_io_lock); 2558158737Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 2559250496Ssmh mtx_unlock(&sc->mfi_io_lock); 2560158737Sambrisko return (EBUSY); 2561158737Sambrisko } 2562158737Sambrisko 2563234429Sambrisko /* Zero out the MFI frame */ 2564234429Sambrisko context = cm->cm_frame->header.context; 2565234429Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2566234429Sambrisko cm->cm_frame->header.context = context; 2567234429Sambrisko 2568158737Sambrisko abort = &cm->cm_frame->abort; 2569158737Sambrisko abort->header.cmd = MFI_CMD_ABORT; 2570158737Sambrisko abort->header.flags = 0; 2571234429Sambrisko abort->header.scsi_status = 0; 2572243824Sdelphij abort->abort_context = (*cm_abort)->cm_frame->header.context; 2573243824Sdelphij abort->abort_mfi_addr_lo = (uint32_t)(*cm_abort)->cm_frame_busaddr; 2574234429Sambrisko abort->abort_mfi_addr_hi = 2575243824Sdelphij (uint32_t)((uint64_t)(*cm_abort)->cm_frame_busaddr >> 32); 2576158737Sambrisko cm->cm_data = NULL; 2577164375Sscottl cm->cm_flags = MFI_CMD_POLLED; 2578158737Sambrisko 2579250496Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) 2580250496Ssmh device_printf(sc->mfi_dev, "failed to abort command\n"); 2581158737Sambrisko mfi_release_command(cm); 2582158737Sambrisko 2583243824Sdelphij mtx_unlock(&sc->mfi_io_lock); 2584243824Sdelphij while (i < 5 && *cm_abort != NULL) { 2585243824Sdelphij tsleep(cm_abort, 0, "mfiabort", 2586234429Sambrisko 5 * hz); 2587165225Sambrisko i++; 2588158737Sambrisko } 2589243824Sdelphij if (*cm_abort != NULL) { 2590243824Sdelphij /* Force a complete if command didn't abort */ 2591243824Sdelphij mtx_lock(&sc->mfi_io_lock); 2592243824Sdelphij (*cm_abort)->cm_complete(*cm_abort); 2593243824Sdelphij mtx_unlock(&sc->mfi_io_lock); 2594235135Sambrisko } 2595158737Sambrisko 2596250496Ssmh return (error); 2597158737Sambrisko} 2598158737Sambrisko 2599157114Sscottlint 2600234429Sambriskomfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, 2601234429Sambrisko int len) 2602157114Sscottl{ 2603157114Sscottl struct mfi_command *cm; 2604157114Sscottl struct mfi_io_frame *io; 2605157114Sscottl int error; 2606234429Sambrisko uint32_t context = 0; 2607157114Sscottl 2608157114Sscottl if ((cm = mfi_dequeue_free(sc)) == NULL) 2609157114Sscottl return (EBUSY); 2610157114Sscottl 2611234429Sambrisko /* Zero out the MFI frame */ 2612234429Sambrisko context = cm->cm_frame->header.context; 2613234429Sambrisko bzero(cm->cm_frame, sizeof(union mfi_frame)); 2614234429Sambrisko cm->cm_frame->header.context = context; 2615234429Sambrisko 2616157114Sscottl io = &cm->cm_frame->io; 2617157114Sscottl io->header.cmd = MFI_CMD_LD_WRITE; 2618157114Sscottl io->header.target_id = id; 2619157114Sscottl io->header.timeout = 0; 2620157114Sscottl io->header.flags = 0; 2621234429Sambrisko io->header.scsi_status = 0; 2622157114Sscottl io->header.sense_len = MFI_SENSE_LEN; 2623157114Sscottl io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2624234429Sambrisko io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2625234429Sambrisko io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2626157114Sscottl io->lba_hi = (lba & 0xffffffff00000000) >> 32; 2627157114Sscottl io->lba_lo = lba & 0xffffffff; 2628157114Sscottl cm->cm_data = virt; 2629157114Sscottl cm->cm_len = len; 2630157114Sscottl cm->cm_sg = &io->sgl; 2631157114Sscottl cm->cm_total_frame_size = MFI_IO_FRAME_SIZE; 2632157114Sscottl cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT; 2633157114Sscottl 2634250496Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) 2635250496Ssmh device_printf(sc->mfi_dev, "failed dump blocks\n"); 2636157114Sscottl bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 2637157114Sscottl BUS_DMASYNC_POSTWRITE); 2638157114Sscottl bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2639157114Sscottl mfi_release_command(cm); 2640157114Sscottl 2641157114Sscottl return (error); 2642157114Sscottl} 2643157114Sscottl 2644234429Sambriskoint 2645234429Sambriskomfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, 2646234429Sambrisko int len) 2647234429Sambrisko{ 2648234429Sambrisko struct mfi_command *cm; 2649234429Sambrisko struct mfi_pass_frame *pass; 2650243824Sdelphij int error, readop, cdb_len; 2651243823Sdelphij uint32_t blkcount; 2652234429Sambrisko 2653234429Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) 2654234429Sambrisko return (EBUSY); 2655234429Sambrisko 2656234429Sambrisko pass = &cm->cm_frame->pass; 2657234429Sambrisko bzero(pass->cdb, 16); 2658234429Sambrisko pass->header.cmd = MFI_CMD_PD_SCSI_IO; 2659243824Sdelphij 2660243824Sdelphij readop = 0; 2661234429Sambrisko blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2662243824Sdelphij cdb_len = mfi_build_cdb(readop, 0, lba, blkcount, pass->cdb); 2663234429Sambrisko pass->header.target_id = id; 2664234429Sambrisko pass->header.timeout = 0; 2665234429Sambrisko pass->header.flags = 0; 2666234429Sambrisko pass->header.scsi_status = 0; 2667234429Sambrisko pass->header.sense_len = MFI_SENSE_LEN; 2668234429Sambrisko pass->header.data_len = len; 2669243824Sdelphij pass->header.cdb_len = cdb_len; 2670234429Sambrisko pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2671234429Sambrisko pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2672234429Sambrisko cm->cm_data = virt; 2673234429Sambrisko cm->cm_len = len; 2674234429Sambrisko cm->cm_sg = &pass->sgl; 2675234429Sambrisko cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; 2676243824Sdelphij cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT | MFI_CMD_SCSI; 2677234429Sambrisko 2678250496Ssmh if ((error = mfi_mapcmd(sc, cm)) != 0) 2679250496Ssmh device_printf(sc->mfi_dev, "failed dump blocks\n"); 2680234429Sambrisko bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 2681234429Sambrisko BUS_DMASYNC_POSTWRITE); 2682234429Sambrisko bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2683234429Sambrisko mfi_release_command(cm); 2684234429Sambrisko 2685234429Sambrisko return (error); 2686234429Sambrisko} 2687234429Sambrisko 2688157114Sscottlstatic int 2689192450Simpmfi_open(struct cdev *dev, int flags, int fmt, struct thread *td) 2690157114Sscottl{ 2691157114Sscottl struct mfi_softc *sc; 2692171822Sjhb int error; 2693157114Sscottl 2694157114Sscottl sc = dev->si_drv1; 2695163398Sscottl 2696163398Sscottl mtx_lock(&sc->mfi_io_lock); 2697171822Sjhb if (sc->mfi_detaching) 2698171822Sjhb error = ENXIO; 2699171822Sjhb else { 2700171822Sjhb sc->mfi_flags |= MFI_FLAGS_OPEN; 2701171822Sjhb error = 0; 2702171822Sjhb } 2703163398Sscottl mtx_unlock(&sc->mfi_io_lock); 2704157114Sscottl 2705171822Sjhb return (error); 2706157114Sscottl} 2707157114Sscottl 2708157114Sscottlstatic int 2709192450Simpmfi_close(struct cdev *dev, int flags, int fmt, struct thread *td) 2710157114Sscottl{ 2711157114Sscottl struct mfi_softc *sc; 2712163398Sscottl struct mfi_aen *mfi_aen_entry, *tmp; 2713157114Sscottl 2714157114Sscottl sc = dev->si_drv1; 2715163398Sscottl 2716163398Sscottl mtx_lock(&sc->mfi_io_lock); 2717157114Sscottl sc->mfi_flags &= ~MFI_FLAGS_OPEN; 2718157114Sscottl 2719163398Sscottl TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) { 2720158737Sambrisko if (mfi_aen_entry->p == curproc) { 2721158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 2722158737Sambrisko aen_link); 2723158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 2724158737Sambrisko } 2725158737Sambrisko } 2726163398Sscottl mtx_unlock(&sc->mfi_io_lock); 2727157114Sscottl return (0); 2728157114Sscottl} 2729157114Sscottl 2730157114Sscottlstatic int 2731171821Sjhbmfi_config_lock(struct mfi_softc *sc, uint32_t opcode) 2732171821Sjhb{ 2733171821Sjhb 2734171821Sjhb switch (opcode) { 2735171821Sjhb case MFI_DCMD_LD_DELETE: 2736171821Sjhb case MFI_DCMD_CFG_ADD: 2737171821Sjhb case MFI_DCMD_CFG_CLEAR: 2738241324Sjhb case MFI_DCMD_CFG_FOREIGN_IMPORT: 2739171821Sjhb sx_xlock(&sc->mfi_config_lock); 2740171821Sjhb return (1); 2741171821Sjhb default: 2742171821Sjhb return (0); 2743171821Sjhb } 2744171821Sjhb} 2745171821Sjhb 2746171821Sjhbstatic void 2747171821Sjhbmfi_config_unlock(struct mfi_softc *sc, int locked) 2748171821Sjhb{ 2749171821Sjhb 2750171821Sjhb if (locked) 2751171821Sjhb sx_xunlock(&sc->mfi_config_lock); 2752171821Sjhb} 2753171821Sjhb 2754234429Sambrisko/* 2755234429Sambrisko * Perform pre-issue checks on commands from userland and possibly veto 2756234429Sambrisko * them. 2757234429Sambrisko */ 2758171821Sjhbstatic int 2759171821Sjhbmfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm) 2760171821Sjhb{ 2761171821Sjhb struct mfi_disk *ld, *ld2; 2762171821Sjhb int error; 2763234429Sambrisko struct mfi_system_pd *syspd = NULL; 2764234429Sambrisko uint16_t syspd_id; 2765234429Sambrisko uint16_t *mbox; 2766171821Sjhb 2767171821Sjhb mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2768171821Sjhb error = 0; 2769171821Sjhb switch (cm->cm_frame->dcmd.opcode) { 2770171821Sjhb case MFI_DCMD_LD_DELETE: 2771171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2772171821Sjhb if (ld->ld_id == cm->cm_frame->dcmd.mbox[0]) 2773171821Sjhb break; 2774171821Sjhb } 2775171821Sjhb if (ld == NULL) 2776171821Sjhb error = ENOENT; 2777171821Sjhb else 2778171821Sjhb error = mfi_disk_disable(ld); 2779171821Sjhb break; 2780171821Sjhb case MFI_DCMD_CFG_CLEAR: 2781171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2782171821Sjhb error = mfi_disk_disable(ld); 2783171821Sjhb if (error) 2784171821Sjhb break; 2785171821Sjhb } 2786171821Sjhb if (error) { 2787171821Sjhb TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) { 2788171821Sjhb if (ld2 == ld) 2789171821Sjhb break; 2790171821Sjhb mfi_disk_enable(ld2); 2791171821Sjhb } 2792171821Sjhb } 2793171821Sjhb break; 2794234429Sambrisko case MFI_DCMD_PD_STATE_SET: 2795234429Sambrisko mbox = (uint16_t *) cm->cm_frame->dcmd.mbox; 2796234429Sambrisko syspd_id = mbox[0]; 2797234429Sambrisko if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { 2798234429Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { 2799234429Sambrisko if (syspd->pd_id == syspd_id) 2800234429Sambrisko break; 2801234429Sambrisko } 2802234429Sambrisko } 2803234429Sambrisko else 2804234429Sambrisko break; 2805234429Sambrisko if (syspd) 2806234429Sambrisko error = mfi_syspd_disable(syspd); 2807234429Sambrisko break; 2808171821Sjhb default: 2809171821Sjhb break; 2810171821Sjhb } 2811171821Sjhb return (error); 2812171821Sjhb} 2813171821Sjhb 2814171821Sjhb/* Perform post-issue checks on commands from userland. */ 2815171821Sjhbstatic void 2816171821Sjhbmfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm) 2817171821Sjhb{ 2818171821Sjhb struct mfi_disk *ld, *ldn; 2819234429Sambrisko struct mfi_system_pd *syspd = NULL; 2820234429Sambrisko uint16_t syspd_id; 2821234429Sambrisko uint16_t *mbox; 2822171821Sjhb 2823171821Sjhb switch (cm->cm_frame->dcmd.opcode) { 2824171821Sjhb case MFI_DCMD_LD_DELETE: 2825171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2826171821Sjhb if (ld->ld_id == cm->cm_frame->dcmd.mbox[0]) 2827171821Sjhb break; 2828171821Sjhb } 2829171821Sjhb KASSERT(ld != NULL, ("volume dissappeared")); 2830171821Sjhb if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { 2831171821Sjhb mtx_unlock(&sc->mfi_io_lock); 2832196403Sjhb mtx_lock(&Giant); 2833171821Sjhb device_delete_child(sc->mfi_dev, ld->ld_dev); 2834196403Sjhb mtx_unlock(&Giant); 2835171821Sjhb mtx_lock(&sc->mfi_io_lock); 2836171821Sjhb } else 2837171821Sjhb mfi_disk_enable(ld); 2838171821Sjhb break; 2839171821Sjhb case MFI_DCMD_CFG_CLEAR: 2840171821Sjhb if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { 2841171821Sjhb mtx_unlock(&sc->mfi_io_lock); 2842196403Sjhb mtx_lock(&Giant); 2843171821Sjhb TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) { 2844171821Sjhb device_delete_child(sc->mfi_dev, ld->ld_dev); 2845171821Sjhb } 2846196403Sjhb mtx_unlock(&Giant); 2847171821Sjhb mtx_lock(&sc->mfi_io_lock); 2848171821Sjhb } else { 2849171821Sjhb TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) 2850171821Sjhb mfi_disk_enable(ld); 2851171821Sjhb } 2852171821Sjhb break; 2853171821Sjhb case MFI_DCMD_CFG_ADD: 2854171821Sjhb mfi_ldprobe(sc); 2855171821Sjhb break; 2856184897Sambrisko case MFI_DCMD_CFG_FOREIGN_IMPORT: 2857184897Sambrisko mfi_ldprobe(sc); 2858184897Sambrisko break; 2859234429Sambrisko case MFI_DCMD_PD_STATE_SET: 2860234429Sambrisko mbox = (uint16_t *) cm->cm_frame->dcmd.mbox; 2861234429Sambrisko syspd_id = mbox[0]; 2862234429Sambrisko if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { 2863234429Sambrisko TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) { 2864234429Sambrisko if (syspd->pd_id == syspd_id) 2865234429Sambrisko break; 2866234429Sambrisko } 2867234429Sambrisko } 2868234429Sambrisko else 2869234429Sambrisko break; 2870234429Sambrisko /* If the transition fails then enable the syspd again */ 2871234429Sambrisko if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK) 2872234429Sambrisko mfi_syspd_enable(syspd); 2873234429Sambrisko break; 2874171821Sjhb } 2875171821Sjhb} 2876171821Sjhb 2877243824Sdelphijstatic int 2878243824Sdelphijmfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm) 2879234429Sambrisko{ 2880243824Sdelphij struct mfi_config_data *conf_data; 2881234429Sambrisko struct mfi_command *ld_cm = NULL; 2882234429Sambrisko struct mfi_ld_info *ld_info = NULL; 2883243824Sdelphij struct mfi_ld_config *ld; 2884243824Sdelphij char *p; 2885234429Sambrisko int error = 0; 2886234429Sambrisko 2887243824Sdelphij conf_data = (struct mfi_config_data *)cm->cm_data; 2888243824Sdelphij 2889243824Sdelphij if (cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) { 2890243824Sdelphij p = (char *)conf_data->array; 2891243824Sdelphij p += conf_data->array_size * conf_data->array_count; 2892243824Sdelphij ld = (struct mfi_ld_config *)p; 2893243824Sdelphij if (ld->params.isSSCD == 1) 2894243824Sdelphij error = 1; 2895234429Sambrisko } else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) { 2896234429Sambrisko error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO, 2897234429Sambrisko (void **)&ld_info, sizeof(*ld_info)); 2898235135Sambrisko if (error) { 2899234429Sambrisko device_printf(sc->mfi_dev, "Failed to allocate" 2900234429Sambrisko "MFI_DCMD_LD_GET_INFO %d", error); 2901234429Sambrisko if (ld_info) 2902234429Sambrisko free(ld_info, M_MFIBUF); 2903234429Sambrisko return 0; 2904234429Sambrisko } 2905234429Sambrisko ld_cm->cm_flags = MFI_CMD_DATAIN; 2906234429Sambrisko ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0]; 2907234429Sambrisko ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0]; 2908235135Sambrisko if (mfi_wait_command(sc, ld_cm) != 0) { 2909234429Sambrisko device_printf(sc->mfi_dev, "failed to get log drv\n"); 2910234429Sambrisko mfi_release_command(ld_cm); 2911234429Sambrisko free(ld_info, M_MFIBUF); 2912234429Sambrisko return 0; 2913234429Sambrisko } 2914234429Sambrisko 2915234429Sambrisko if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) { 2916234429Sambrisko free(ld_info, M_MFIBUF); 2917234429Sambrisko mfi_release_command(ld_cm); 2918234429Sambrisko return 0; 2919234429Sambrisko } 2920234429Sambrisko else 2921234429Sambrisko ld_info = (struct mfi_ld_info *)ld_cm->cm_private; 2922234429Sambrisko 2923234429Sambrisko if (ld_info->ld_config.params.isSSCD == 1) 2924234429Sambrisko error = 1; 2925234429Sambrisko 2926234429Sambrisko mfi_release_command(ld_cm); 2927234429Sambrisko free(ld_info, M_MFIBUF); 2928234429Sambrisko 2929234429Sambrisko } 2930234429Sambrisko return error; 2931234429Sambrisko} 2932234429Sambrisko 2933171821Sjhbstatic int 2934234429Sambriskomfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg) 2935234429Sambrisko{ 2936234429Sambrisko uint8_t i; 2937234429Sambrisko struct mfi_ioc_packet *ioc; 2938234429Sambrisko ioc = (struct mfi_ioc_packet *)arg; 2939234429Sambrisko int sge_size, error; 2940234429Sambrisko struct megasas_sge *kern_sge; 2941234429Sambrisko 2942234429Sambrisko memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr)); 2943234429Sambrisko kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off); 2944234429Sambrisko cm->cm_frame->header.sg_count = ioc->mfi_sge_count; 2945234429Sambrisko 2946234429Sambrisko if (sizeof(bus_addr_t) == 8) { 2947234429Sambrisko cm->cm_frame->header.flags |= MFI_FRAME_SGL64; 2948234429Sambrisko cm->cm_extra_frames = 2; 2949234429Sambrisko sge_size = sizeof(struct mfi_sg64); 2950234429Sambrisko } else { 2951234429Sambrisko cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; 2952234429Sambrisko sge_size = sizeof(struct mfi_sg32); 2953234429Sambrisko } 2954234429Sambrisko 2955234429Sambrisko cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count); 2956234429Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 2957234429Sambrisko if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 2958234429Sambrisko 1, 0, /* algnmnt, boundary */ 2959234429Sambrisko BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 2960234429Sambrisko BUS_SPACE_MAXADDR, /* highaddr */ 2961234429Sambrisko NULL, NULL, /* filter, filterarg */ 2962234429Sambrisko ioc->mfi_sgl[i].iov_len,/* maxsize */ 2963234429Sambrisko 2, /* nsegments */ 2964234429Sambrisko ioc->mfi_sgl[i].iov_len,/* maxsegsize */ 2965234429Sambrisko BUS_DMA_ALLOCNOW, /* flags */ 2966234429Sambrisko NULL, NULL, /* lockfunc, lockarg */ 2967234429Sambrisko &sc->mfi_kbuff_arr_dmat[i])) { 2968234429Sambrisko device_printf(sc->mfi_dev, 2969234429Sambrisko "Cannot allocate mfi_kbuff_arr_dmat tag\n"); 2970234429Sambrisko return (ENOMEM); 2971234429Sambrisko } 2972234429Sambrisko 2973234429Sambrisko if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i], 2974234429Sambrisko (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT, 2975234429Sambrisko &sc->mfi_kbuff_arr_dmamap[i])) { 2976234429Sambrisko device_printf(sc->mfi_dev, 2977234429Sambrisko "Cannot allocate mfi_kbuff_arr_dmamap memory\n"); 2978234429Sambrisko return (ENOMEM); 2979234429Sambrisko } 2980234429Sambrisko 2981234429Sambrisko bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i], 2982234429Sambrisko sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i], 2983234429Sambrisko ioc->mfi_sgl[i].iov_len, mfi_addr_cb, 2984234429Sambrisko &sc->mfi_kbuff_arr_busaddr[i], 0); 2985234429Sambrisko 2986234429Sambrisko if (!sc->kbuff_arr[i]) { 2987234429Sambrisko device_printf(sc->mfi_dev, 2988234429Sambrisko "Could not allocate memory for kbuff_arr info\n"); 2989234429Sambrisko return -1; 2990234429Sambrisko } 2991234429Sambrisko kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i]; 2992234429Sambrisko kern_sge[i].length = ioc->mfi_sgl[i].iov_len; 2993234429Sambrisko 2994234429Sambrisko if (sizeof(bus_addr_t) == 8) { 2995234429Sambrisko cm->cm_frame->stp.sgl.sg64[i].addr = 2996234429Sambrisko kern_sge[i].phys_addr; 2997234429Sambrisko cm->cm_frame->stp.sgl.sg64[i].len = 2998234429Sambrisko ioc->mfi_sgl[i].iov_len; 2999234429Sambrisko } else { 3000247828Sdelphij cm->cm_frame->stp.sgl.sg32[i].addr = 3001234429Sambrisko kern_sge[i].phys_addr; 3002234429Sambrisko cm->cm_frame->stp.sgl.sg32[i].len = 3003234429Sambrisko ioc->mfi_sgl[i].iov_len; 3004234429Sambrisko } 3005234429Sambrisko 3006234429Sambrisko error = copyin(ioc->mfi_sgl[i].iov_base, 3007234429Sambrisko sc->kbuff_arr[i], 3008234429Sambrisko ioc->mfi_sgl[i].iov_len); 3009234429Sambrisko if (error != 0) { 3010234429Sambrisko device_printf(sc->mfi_dev, "Copy in failed\n"); 3011234429Sambrisko return error; 3012234429Sambrisko } 3013234429Sambrisko } 3014234429Sambrisko 3015234429Sambrisko cm->cm_flags |=MFI_CMD_MAPPED; 3016234429Sambrisko return 0; 3017234429Sambrisko} 3018234429Sambrisko 3019234429Sambriskostatic int 3020178968Sscottlmfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc) 3021178968Sscottl{ 3022178968Sscottl struct mfi_command *cm; 3023178968Sscottl struct mfi_dcmd_frame *dcmd; 3024178968Sscottl void *ioc_buf = NULL; 3025178968Sscottl uint32_t context; 3026178968Sscottl int error = 0, locked; 3027178968Sscottl 3028178968Sscottl 3029178968Sscottl if (ioc->buf_size > 0) { 3030239866Sjhb if (ioc->buf_size > 1024 * 1024) 3031239866Sjhb return (ENOMEM); 3032178968Sscottl ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK); 3033178968Sscottl error = copyin(ioc->buf, ioc_buf, ioc->buf_size); 3034178968Sscottl if (error) { 3035178968Sscottl device_printf(sc->mfi_dev, "failed to copyin\n"); 3036178968Sscottl free(ioc_buf, M_MFIBUF); 3037178968Sscottl return (error); 3038178968Sscottl } 3039178968Sscottl } 3040178968Sscottl 3041178968Sscottl locked = mfi_config_lock(sc, ioc->ioc_frame.opcode); 3042178968Sscottl 3043178968Sscottl mtx_lock(&sc->mfi_io_lock); 3044178968Sscottl while ((cm = mfi_dequeue_free(sc)) == NULL) 3045178968Sscottl msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz); 3046178968Sscottl 3047178968Sscottl /* Save context for later */ 3048178968Sscottl context = cm->cm_frame->header.context; 3049178968Sscottl 3050178968Sscottl dcmd = &cm->cm_frame->dcmd; 3051178968Sscottl bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame)); 3052178968Sscottl 3053178968Sscottl cm->cm_sg = &dcmd->sgl; 3054178968Sscottl cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 3055178968Sscottl cm->cm_data = ioc_buf; 3056178968Sscottl cm->cm_len = ioc->buf_size; 3057178968Sscottl 3058178968Sscottl /* restore context */ 3059178968Sscottl cm->cm_frame->header.context = context; 3060178968Sscottl 3061178968Sscottl /* Cheat since we don't know if we're writing or reading */ 3062178968Sscottl cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT; 3063178968Sscottl 3064178968Sscottl error = mfi_check_command_pre(sc, cm); 3065178968Sscottl if (error) 3066178968Sscottl goto out; 3067178968Sscottl 3068178968Sscottl error = mfi_wait_command(sc, cm); 3069178968Sscottl if (error) { 3070178968Sscottl device_printf(sc->mfi_dev, "ioctl failed %d\n", error); 3071178968Sscottl goto out; 3072178968Sscottl } 3073178968Sscottl bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame)); 3074178968Sscottl mfi_check_command_post(sc, cm); 3075178968Sscottlout: 3076178968Sscottl mfi_release_command(cm); 3077178968Sscottl mtx_unlock(&sc->mfi_io_lock); 3078178968Sscottl mfi_config_unlock(sc, locked); 3079178968Sscottl if (ioc->buf_size > 0) 3080178968Sscottl error = copyout(ioc_buf, ioc->buf, ioc->buf_size); 3081178968Sscottl if (ioc_buf) 3082178968Sscottl free(ioc_buf, M_MFIBUF); 3083178968Sscottl return (error); 3084178968Sscottl} 3085178968Sscottl 3086178968Sscottl#define PTRIN(p) ((void *)(uintptr_t)(p)) 3087178968Sscottl 3088178968Sscottlstatic int 3089192450Simpmfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 3090157114Sscottl{ 3091157114Sscottl struct mfi_softc *sc; 3092157114Sscottl union mfi_statrequest *ms; 3093164281Sambrisko struct mfi_ioc_packet *ioc; 3094234429Sambrisko#ifdef COMPAT_FREEBSD32 3095179392Sambrisko struct mfi_ioc_packet32 *ioc32; 3096179392Sambrisko#endif 3097164281Sambrisko struct mfi_ioc_aen *aen; 3098164281Sambrisko struct mfi_command *cm = NULL; 3099234429Sambrisko uint32_t context = 0; 3100184897Sambrisko union mfi_sense_ptr sense_ptr; 3101234429Sambrisko uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0; 3102225918Smav size_t len; 3103234429Sambrisko int i, res; 3104178968Sscottl struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg; 3105234429Sambrisko#ifdef COMPAT_FREEBSD32 3106178968Sscottl struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg; 3107178968Sscottl struct mfi_ioc_passthru iop_swab; 3108178968Sscottl#endif 3109171821Sjhb int error, locked; 3110234429Sambrisko union mfi_sgl *sgl; 3111157114Sscottl sc = dev->si_drv1; 3112157114Sscottl error = 0; 3113157114Sscottl 3114234429Sambrisko if (sc->adpreset) 3115234429Sambrisko return EBUSY; 3116234429Sambrisko 3117234429Sambrisko if (sc->hw_crit_error) 3118234429Sambrisko return EBUSY; 3119234429Sambrisko 3120234429Sambrisko if (sc->issuepend_done == 0) 3121234429Sambrisko return EBUSY; 3122234429Sambrisko 3123157114Sscottl switch (cmd) { 3124157114Sscottl case MFIIO_STATS: 3125157114Sscottl ms = (union mfi_statrequest *)arg; 3126157114Sscottl switch (ms->ms_item) { 3127157114Sscottl case MFIQ_FREE: 3128157114Sscottl case MFIQ_BIO: 3129157114Sscottl case MFIQ_READY: 3130157114Sscottl case MFIQ_BUSY: 3131157114Sscottl bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat, 3132157114Sscottl sizeof(struct mfi_qstat)); 3133157114Sscottl break; 3134157114Sscottl default: 3135158737Sambrisko error = ENOIOCTL; 3136157114Sscottl break; 3137157114Sscottl } 3138157114Sscottl break; 3139169451Sscottl case MFIIO_QUERY_DISK: 3140169451Sscottl { 3141169451Sscottl struct mfi_query_disk *qd; 3142169451Sscottl struct mfi_disk *ld; 3143169451Sscottl 3144169451Sscottl qd = (struct mfi_query_disk *)arg; 3145169451Sscottl mtx_lock(&sc->mfi_io_lock); 3146169451Sscottl TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 3147169451Sscottl if (ld->ld_id == qd->array_id) 3148169451Sscottl break; 3149169451Sscottl } 3150169451Sscottl if (ld == NULL) { 3151169451Sscottl qd->present = 0; 3152169451Sscottl mtx_unlock(&sc->mfi_io_lock); 3153169451Sscottl return (0); 3154169451Sscottl } 3155169451Sscottl qd->present = 1; 3156169451Sscottl if (ld->ld_flags & MFI_DISK_FLAGS_OPEN) 3157169451Sscottl qd->open = 1; 3158169451Sscottl bzero(qd->devname, SPECNAMELEN + 1); 3159169451Sscottl snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit); 3160169451Sscottl mtx_unlock(&sc->mfi_io_lock); 3161169451Sscottl break; 3162169451Sscottl } 3163164281Sambrisko case MFI_CMD: 3164234429Sambrisko#ifdef COMPAT_FREEBSD32 3165179392Sambrisko case MFI_CMD32: 3166179392Sambrisko#endif 3167177489Sambrisko { 3168177489Sambrisko devclass_t devclass; 3169164281Sambrisko ioc = (struct mfi_ioc_packet *)arg; 3170177489Sambrisko int adapter; 3171164281Sambrisko 3172177489Sambrisko adapter = ioc->mfi_adapter_no; 3173177489Sambrisko if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) { 3174177489Sambrisko devclass = devclass_find("mfi"); 3175177489Sambrisko sc = devclass_get_softc(devclass, adapter); 3176177489Sambrisko } 3177164281Sambrisko mtx_lock(&sc->mfi_io_lock); 3178164281Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 3179164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3180164281Sambrisko return (EBUSY); 3181164281Sambrisko } 3182164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3183171821Sjhb locked = 0; 3184164281Sambrisko 3185164281Sambrisko /* 3186164281Sambrisko * save off original context since copying from user 3187164281Sambrisko * will clobber some data 3188164281Sambrisko */ 3189164281Sambrisko context = cm->cm_frame->header.context; 3190234429Sambrisko cm->cm_frame->header.context = cm->cm_index; 3191164281Sambrisko 3192165225Sambrisko bcopy(ioc->mfi_frame.raw, cm->cm_frame, 3193234429Sambrisko 2 * MEGAMFI_FRAME_SIZE); 3194184897Sambrisko cm->cm_total_frame_size = (sizeof(union mfi_sgl) 3195184897Sambrisko * ioc->mfi_sge_count) + ioc->mfi_sgl_off; 3196234429Sambrisko cm->cm_frame->header.scsi_status = 0; 3197234429Sambrisko cm->cm_frame->header.pad0 = 0; 3198175897Sambrisko if (ioc->mfi_sge_count) { 3199175897Sambrisko cm->cm_sg = 3200175897Sambrisko (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off]; 3201175897Sambrisko } 3202234429Sambrisko sgl = cm->cm_sg; 3203175897Sambrisko cm->cm_flags = 0; 3204175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN) 3205175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN; 3206175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT) 3207175897Sambrisko cm->cm_flags |= MFI_CMD_DATAOUT; 3208175897Sambrisko /* Legacy app shim */ 3209175897Sambrisko if (cm->cm_flags == 0) 3210175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT; 3211164281Sambrisko cm->cm_len = cm->cm_frame->header.data_len; 3212225918Smav if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3213234429Sambrisko#ifdef COMPAT_FREEBSD32 3214225918Smav if (cmd == MFI_CMD) { 3215225918Smav#endif 3216225918Smav /* Native */ 3217225918Smav cm->cm_stp_len = ioc->mfi_sgl[0].iov_len; 3218234429Sambrisko#ifdef COMPAT_FREEBSD32 3219225918Smav } else { 3220225918Smav /* 32bit on 64bit */ 3221225918Smav ioc32 = (struct mfi_ioc_packet32 *)ioc; 3222225918Smav cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len; 3223225918Smav } 3224225918Smav#endif 3225225918Smav cm->cm_len += cm->cm_stp_len; 3226225918Smav } 3227184897Sambrisko if (cm->cm_len && 3228184897Sambrisko (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) { 3229175897Sambrisko cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF, 3230175897Sambrisko M_WAITOK | M_ZERO); 3231175897Sambrisko if (cm->cm_data == NULL) { 3232175897Sambrisko device_printf(sc->mfi_dev, "Malloc failed\n"); 3233175897Sambrisko goto out; 3234175897Sambrisko } 3235175897Sambrisko } else { 3236175897Sambrisko cm->cm_data = 0; 3237165225Sambrisko } 3238164281Sambrisko 3239164281Sambrisko /* restore header context */ 3240164281Sambrisko cm->cm_frame->header.context = context; 3241164281Sambrisko 3242234429Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3243234429Sambrisko res = mfi_stp_cmd(sc, cm, arg); 3244234429Sambrisko if (res != 0) 3245234429Sambrisko goto out; 3246234429Sambrisko } else { 3247234429Sambrisko temp = data; 3248234429Sambrisko if ((cm->cm_flags & MFI_CMD_DATAOUT) || 3249234429Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_STP)) { 3250234429Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 3251234429Sambrisko#ifdef COMPAT_FREEBSD32 3252234429Sambrisko if (cmd == MFI_CMD) { 3253225918Smav#endif 3254234429Sambrisko /* Native */ 3255234429Sambrisko addr = ioc->mfi_sgl[i].iov_base; 3256234429Sambrisko len = ioc->mfi_sgl[i].iov_len; 3257234429Sambrisko#ifdef COMPAT_FREEBSD32 3258234429Sambrisko } else { 3259234429Sambrisko /* 32bit on 64bit */ 3260234429Sambrisko ioc32 = (struct mfi_ioc_packet32 *)ioc; 3261234429Sambrisko addr = PTRIN(ioc32->mfi_sgl[i].iov_base); 3262234429Sambrisko len = ioc32->mfi_sgl[i].iov_len; 3263234429Sambrisko } 3264179392Sambrisko#endif 3265234429Sambrisko error = copyin(addr, temp, len); 3266234429Sambrisko if (error != 0) { 3267234429Sambrisko device_printf(sc->mfi_dev, 3268234429Sambrisko "Copy in failed\n"); 3269234429Sambrisko goto out; 3270234429Sambrisko } 3271234429Sambrisko temp = &temp[len]; 3272175897Sambrisko } 3273164281Sambrisko } 3274164281Sambrisko } 3275164281Sambrisko 3276171821Sjhb if (cm->cm_frame->header.cmd == MFI_CMD_DCMD) 3277234429Sambrisko locked = mfi_config_lock(sc, 3278234429Sambrisko cm->cm_frame->dcmd.opcode); 3279171821Sjhb 3280184933Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { 3281234429Sambrisko cm->cm_frame->pass.sense_addr_lo = 3282234429Sambrisko (uint32_t)cm->cm_sense_busaddr; 3283234429Sambrisko cm->cm_frame->pass.sense_addr_hi = 3284234429Sambrisko (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 3285184933Sambrisko } 3286164281Sambrisko mtx_lock(&sc->mfi_io_lock); 3287234429Sambrisko skip_pre_post = mfi_check_for_sscd (sc, cm); 3288234429Sambrisko if (!skip_pre_post) { 3289234429Sambrisko error = mfi_check_command_pre(sc, cm); 3290234429Sambrisko if (error) { 3291234429Sambrisko mtx_unlock(&sc->mfi_io_lock); 3292234429Sambrisko goto out; 3293234429Sambrisko } 3294171821Sjhb } 3295170284Sambrisko if ((error = mfi_wait_command(sc, cm)) != 0) { 3296164281Sambrisko device_printf(sc->mfi_dev, 3297165225Sambrisko "Controller polled failed\n"); 3298164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3299164281Sambrisko goto out; 3300164281Sambrisko } 3301234429Sambrisko if (!skip_pre_post) { 3302234429Sambrisko mfi_check_command_post(sc, cm); 3303234429Sambrisko } 3304164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3305164281Sambrisko 3306234429Sambrisko if (cm->cm_frame->header.cmd != MFI_CMD_STP) { 3307234429Sambrisko temp = data; 3308234429Sambrisko if ((cm->cm_flags & MFI_CMD_DATAIN) || 3309234429Sambrisko (cm->cm_frame->header.cmd == MFI_CMD_STP)) { 3310234429Sambrisko for (i = 0; i < ioc->mfi_sge_count; i++) { 3311234429Sambrisko#ifdef COMPAT_FREEBSD32 3312234429Sambrisko if (cmd == MFI_CMD) { 3313225918Smav#endif 3314234429Sambrisko /* Native */ 3315234429Sambrisko addr = ioc->mfi_sgl[i].iov_base; 3316234429Sambrisko len = ioc->mfi_sgl[i].iov_len; 3317234429Sambrisko#ifdef COMPAT_FREEBSD32 3318234429Sambrisko } else { 3319234429Sambrisko /* 32bit on 64bit */ 3320234429Sambrisko ioc32 = (struct mfi_ioc_packet32 *)ioc; 3321234429Sambrisko addr = PTRIN(ioc32->mfi_sgl[i].iov_base); 3322234429Sambrisko len = ioc32->mfi_sgl[i].iov_len; 3323234429Sambrisko } 3324179392Sambrisko#endif 3325234429Sambrisko error = copyout(temp, addr, len); 3326234429Sambrisko if (error != 0) { 3327234429Sambrisko device_printf(sc->mfi_dev, 3328234429Sambrisko "Copy out failed\n"); 3329234429Sambrisko goto out; 3330234429Sambrisko } 3331234429Sambrisko temp = &temp[len]; 3332175897Sambrisko } 3333164281Sambrisko } 3334164281Sambrisko } 3335164281Sambrisko 3336165225Sambrisko if (ioc->mfi_sense_len) { 3337184897Sambrisko /* get user-space sense ptr then copy out sense */ 3338225428Sbz bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off], 3339184897Sambrisko &sense_ptr.sense_ptr_data[0], 3340184897Sambrisko sizeof(sense_ptr.sense_ptr_data)); 3341234429Sambrisko#ifdef COMPAT_FREEBSD32 3342184974Sambrisko if (cmd != MFI_CMD) { 3343184974Sambrisko /* 3344184974Sambrisko * not 64bit native so zero out any address 3345184974Sambrisko * over 32bit */ 3346184975Sambrisko sense_ptr.addr.high = 0; 3347184974Sambrisko } 3348184974Sambrisko#endif 3349184897Sambrisko error = copyout(cm->cm_sense, sense_ptr.user_space, 3350165225Sambrisko ioc->mfi_sense_len); 3351164281Sambrisko if (error != 0) { 3352164281Sambrisko device_printf(sc->mfi_dev, 3353165225Sambrisko "Copy out failed\n"); 3354164281Sambrisko goto out; 3355164281Sambrisko } 3356164281Sambrisko } 3357164281Sambrisko 3358165225Sambrisko ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status; 3359164281Sambriskoout: 3360171821Sjhb mfi_config_unlock(sc, locked); 3361164281Sambrisko if (data) 3362164281Sambrisko free(data, M_MFIBUF); 3363234429Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3364234429Sambrisko for (i = 0; i < 2; i++) { 3365234429Sambrisko if (sc->kbuff_arr[i]) { 3366234429Sambrisko if (sc->mfi_kbuff_arr_busaddr != 0) 3367234429Sambrisko bus_dmamap_unload( 3368234429Sambrisko sc->mfi_kbuff_arr_dmat[i], 3369234429Sambrisko sc->mfi_kbuff_arr_dmamap[i] 3370234429Sambrisko ); 3371234429Sambrisko if (sc->kbuff_arr[i] != NULL) 3372234429Sambrisko bus_dmamem_free( 3373234429Sambrisko sc->mfi_kbuff_arr_dmat[i], 3374234429Sambrisko sc->kbuff_arr[i], 3375234429Sambrisko sc->mfi_kbuff_arr_dmamap[i] 3376234429Sambrisko ); 3377234429Sambrisko if (sc->mfi_kbuff_arr_dmat[i] != NULL) 3378234429Sambrisko bus_dma_tag_destroy( 3379234429Sambrisko sc->mfi_kbuff_arr_dmat[i]); 3380234429Sambrisko } 3381234429Sambrisko } 3382234429Sambrisko } 3383164281Sambrisko if (cm) { 3384164281Sambrisko mtx_lock(&sc->mfi_io_lock); 3385164281Sambrisko mfi_release_command(cm); 3386164281Sambrisko mtx_unlock(&sc->mfi_io_lock); 3387164281Sambrisko } 3388164281Sambrisko 3389164281Sambrisko break; 3390177489Sambrisko } 3391164281Sambrisko case MFI_SET_AEN: 3392164281Sambrisko aen = (struct mfi_ioc_aen *)arg; 3393250496Ssmh mtx_lock(&sc->mfi_io_lock); 3394164281Sambrisko error = mfi_aen_register(sc, aen->aen_seq_num, 3395164281Sambrisko aen->aen_class_locale); 3396250496Ssmh mtx_unlock(&sc->mfi_io_lock); 3397164281Sambrisko 3398164281Sambrisko break; 3399164281Sambrisko case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */ 3400158737Sambrisko { 3401158737Sambrisko devclass_t devclass; 3402158737Sambrisko struct mfi_linux_ioc_packet l_ioc; 3403158737Sambrisko int adapter; 3404158737Sambrisko 3405158737Sambrisko devclass = devclass_find("mfi"); 3406158737Sambrisko if (devclass == NULL) 3407158737Sambrisko return (ENOENT); 3408158737Sambrisko 3409158737Sambrisko error = copyin(arg, &l_ioc, sizeof(l_ioc)); 3410158737Sambrisko if (error) 3411158737Sambrisko return (error); 3412158737Sambrisko adapter = l_ioc.lioc_adapter_no; 3413158737Sambrisko sc = devclass_get_softc(devclass, adapter); 3414158737Sambrisko if (sc == NULL) 3415158737Sambrisko return (ENOENT); 3416158737Sambrisko return (mfi_linux_ioctl_int(sc->mfi_cdev, 3417158737Sambrisko cmd, arg, flag, td)); 3418158737Sambrisko break; 3419158737Sambrisko } 3420164281Sambrisko case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */ 3421158737Sambrisko { 3422158737Sambrisko devclass_t devclass; 3423158737Sambrisko struct mfi_linux_ioc_aen l_aen; 3424158737Sambrisko int adapter; 3425158737Sambrisko 3426158737Sambrisko devclass = devclass_find("mfi"); 3427158737Sambrisko if (devclass == NULL) 3428158737Sambrisko return (ENOENT); 3429158737Sambrisko 3430158737Sambrisko error = copyin(arg, &l_aen, sizeof(l_aen)); 3431158737Sambrisko if (error) 3432158737Sambrisko return (error); 3433158737Sambrisko adapter = l_aen.laen_adapter_no; 3434158737Sambrisko sc = devclass_get_softc(devclass, adapter); 3435158737Sambrisko if (sc == NULL) 3436158737Sambrisko return (ENOENT); 3437158737Sambrisko return (mfi_linux_ioctl_int(sc->mfi_cdev, 3438158737Sambrisko cmd, arg, flag, td)); 3439158737Sambrisko break; 3440158737Sambrisko } 3441234429Sambrisko#ifdef COMPAT_FREEBSD32 3442178968Sscottl case MFIIO_PASSTHRU32: 3443239866Sjhb if (!SV_CURPROC_FLAG(SV_ILP32)) { 3444239866Sjhb error = ENOTTY; 3445239866Sjhb break; 3446239866Sjhb } 3447178968Sscottl iop_swab.ioc_frame = iop32->ioc_frame; 3448178968Sscottl iop_swab.buf_size = iop32->buf_size; 3449178968Sscottl iop_swab.buf = PTRIN(iop32->buf); 3450178968Sscottl iop = &iop_swab; 3451178968Sscottl /* FALLTHROUGH */ 3452178968Sscottl#endif 3453178968Sscottl case MFIIO_PASSTHRU: 3454178968Sscottl error = mfi_user_command(sc, iop); 3455234429Sambrisko#ifdef COMPAT_FREEBSD32 3456178968Sscottl if (cmd == MFIIO_PASSTHRU32) 3457178968Sscottl iop32->ioc_frame = iop_swab.ioc_frame; 3458178968Sscottl#endif 3459178968Sscottl break; 3460157114Sscottl default: 3461163398Sscottl device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); 3462239866Sjhb error = ENOTTY; 3463157114Sscottl break; 3464157114Sscottl } 3465157114Sscottl 3466157114Sscottl return (error); 3467157114Sscottl} 3468158737Sambrisko 3469158737Sambriskostatic int 3470192450Simpmfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 3471158737Sambrisko{ 3472158737Sambrisko struct mfi_softc *sc; 3473158737Sambrisko struct mfi_linux_ioc_packet l_ioc; 3474158737Sambrisko struct mfi_linux_ioc_aen l_aen; 3475158737Sambrisko struct mfi_command *cm = NULL; 3476158737Sambrisko struct mfi_aen *mfi_aen_entry; 3477184897Sambrisko union mfi_sense_ptr sense_ptr; 3478234429Sambrisko uint32_t context = 0; 3479158737Sambrisko uint8_t *data = NULL, *temp; 3480158737Sambrisko int i; 3481171821Sjhb int error, locked; 3482158737Sambrisko 3483158737Sambrisko sc = dev->si_drv1; 3484158737Sambrisko error = 0; 3485158737Sambrisko switch (cmd) { 3486164281Sambrisko case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */ 3487158737Sambrisko error = copyin(arg, &l_ioc, sizeof(l_ioc)); 3488158737Sambrisko if (error != 0) 3489158737Sambrisko return (error); 3490158737Sambrisko 3491158737Sambrisko if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) { 3492158737Sambrisko return (EINVAL); 3493158737Sambrisko } 3494158737Sambrisko 3495158737Sambrisko mtx_lock(&sc->mfi_io_lock); 3496158737Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 3497158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3498158737Sambrisko return (EBUSY); 3499158737Sambrisko } 3500158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3501171821Sjhb locked = 0; 3502158737Sambrisko 3503158737Sambrisko /* 3504158737Sambrisko * save off original context since copying from user 3505158737Sambrisko * will clobber some data 3506158737Sambrisko */ 3507158737Sambrisko context = cm->cm_frame->header.context; 3508158737Sambrisko 3509158737Sambrisko bcopy(l_ioc.lioc_frame.raw, cm->cm_frame, 3510175897Sambrisko 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */ 3511184897Sambrisko cm->cm_total_frame_size = (sizeof(union mfi_sgl) 3512184897Sambrisko * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off; 3513234429Sambrisko cm->cm_frame->header.scsi_status = 0; 3514234429Sambrisko cm->cm_frame->header.pad0 = 0; 3515175897Sambrisko if (l_ioc.lioc_sge_count) 3516175897Sambrisko cm->cm_sg = 3517175897Sambrisko (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off]; 3518175897Sambrisko cm->cm_flags = 0; 3519175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN) 3520175897Sambrisko cm->cm_flags |= MFI_CMD_DATAIN; 3521175897Sambrisko if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT) 3522175897Sambrisko cm->cm_flags |= MFI_CMD_DATAOUT; 3523158737Sambrisko cm->cm_len = cm->cm_frame->header.data_len; 3524184897Sambrisko if (cm->cm_len && 3525184897Sambrisko (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) { 3526175897Sambrisko cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF, 3527175897Sambrisko M_WAITOK | M_ZERO); 3528175897Sambrisko if (cm->cm_data == NULL) { 3529175897Sambrisko device_printf(sc->mfi_dev, "Malloc failed\n"); 3530175897Sambrisko goto out; 3531175897Sambrisko } 3532175897Sambrisko } else { 3533175897Sambrisko cm->cm_data = 0; 3534175897Sambrisko } 3535158737Sambrisko 3536158737Sambrisko /* restore header context */ 3537158737Sambrisko cm->cm_frame->header.context = context; 3538158737Sambrisko 3539158737Sambrisko temp = data; 3540175897Sambrisko if (cm->cm_flags & MFI_CMD_DATAOUT) { 3541175897Sambrisko for (i = 0; i < l_ioc.lioc_sge_count; i++) { 3542178968Sscottl error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base), 3543175897Sambrisko temp, 3544175897Sambrisko l_ioc.lioc_sgl[i].iov_len); 3545175897Sambrisko if (error != 0) { 3546175897Sambrisko device_printf(sc->mfi_dev, 3547175897Sambrisko "Copy in failed\n"); 3548175897Sambrisko goto out; 3549175897Sambrisko } 3550175897Sambrisko temp = &temp[l_ioc.lioc_sgl[i].iov_len]; 3551158737Sambrisko } 3552158737Sambrisko } 3553158737Sambrisko 3554171821Sjhb if (cm->cm_frame->header.cmd == MFI_CMD_DCMD) 3555171821Sjhb locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode); 3556171821Sjhb 3557184933Sambrisko if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { 3558234429Sambrisko cm->cm_frame->pass.sense_addr_lo = 3559234429Sambrisko (uint32_t)cm->cm_sense_busaddr; 3560234429Sambrisko cm->cm_frame->pass.sense_addr_hi = 3561234429Sambrisko (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 3562184933Sambrisko } 3563184933Sambrisko 3564163398Sscottl mtx_lock(&sc->mfi_io_lock); 3565171821Sjhb error = mfi_check_command_pre(sc, cm); 3566171821Sjhb if (error) { 3567171821Sjhb mtx_unlock(&sc->mfi_io_lock); 3568171821Sjhb goto out; 3569171821Sjhb } 3570171821Sjhb 3571170284Sambrisko if ((error = mfi_wait_command(sc, cm)) != 0) { 3572158737Sambrisko device_printf(sc->mfi_dev, 3573165225Sambrisko "Controller polled failed\n"); 3574163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3575158737Sambrisko goto out; 3576158737Sambrisko } 3577158737Sambrisko 3578171821Sjhb mfi_check_command_post(sc, cm); 3579163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3580158737Sambrisko 3581158737Sambrisko temp = data; 3582175897Sambrisko if (cm->cm_flags & MFI_CMD_DATAIN) { 3583175897Sambrisko for (i = 0; i < l_ioc.lioc_sge_count; i++) { 3584175897Sambrisko error = copyout(temp, 3585178968Sscottl PTRIN(l_ioc.lioc_sgl[i].iov_base), 3586175897Sambrisko l_ioc.lioc_sgl[i].iov_len); 3587175897Sambrisko if (error != 0) { 3588175897Sambrisko device_printf(sc->mfi_dev, 3589175897Sambrisko "Copy out failed\n"); 3590175897Sambrisko goto out; 3591175897Sambrisko } 3592175897Sambrisko temp = &temp[l_ioc.lioc_sgl[i].iov_len]; 3593158737Sambrisko } 3594158737Sambrisko } 3595158737Sambrisko 3596158737Sambrisko if (l_ioc.lioc_sense_len) { 3597184897Sambrisko /* get user-space sense ptr then copy out sense */ 3598184897Sambrisko bcopy(&((struct mfi_linux_ioc_packet*)arg) 3599184897Sambrisko ->lioc_frame.raw[l_ioc.lioc_sense_off], 3600184897Sambrisko &sense_ptr.sense_ptr_data[0], 3601184897Sambrisko sizeof(sense_ptr.sense_ptr_data)); 3602184974Sambrisko#ifdef __amd64__ 3603184974Sambrisko /* 3604184974Sambrisko * only 32bit Linux support so zero out any 3605184974Sambrisko * address over 32bit 3606184974Sambrisko */ 3607184975Sambrisko sense_ptr.addr.high = 0; 3608184974Sambrisko#endif 3609184897Sambrisko error = copyout(cm->cm_sense, sense_ptr.user_space, 3610158737Sambrisko l_ioc.lioc_sense_len); 3611158737Sambrisko if (error != 0) { 3612158737Sambrisko device_printf(sc->mfi_dev, 3613165225Sambrisko "Copy out failed\n"); 3614158737Sambrisko goto out; 3615158737Sambrisko } 3616158737Sambrisko } 3617158737Sambrisko 3618158737Sambrisko error = copyout(&cm->cm_frame->header.cmd_status, 3619158737Sambrisko &((struct mfi_linux_ioc_packet*)arg) 3620158737Sambrisko ->lioc_frame.hdr.cmd_status, 3621158737Sambrisko 1); 3622158737Sambrisko if (error != 0) { 3623158737Sambrisko device_printf(sc->mfi_dev, 3624165225Sambrisko "Copy out failed\n"); 3625158737Sambrisko goto out; 3626158737Sambrisko } 3627158737Sambrisko 3628158737Sambriskoout: 3629171821Sjhb mfi_config_unlock(sc, locked); 3630158737Sambrisko if (data) 3631158737Sambrisko free(data, M_MFIBUF); 3632158737Sambrisko if (cm) { 3633158737Sambrisko mtx_lock(&sc->mfi_io_lock); 3634158737Sambrisko mfi_release_command(cm); 3635158737Sambrisko mtx_unlock(&sc->mfi_io_lock); 3636158737Sambrisko } 3637158737Sambrisko 3638158737Sambrisko return (error); 3639164281Sambrisko case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */ 3640158737Sambrisko error = copyin(arg, &l_aen, sizeof(l_aen)); 3641158737Sambrisko if (error != 0) 3642158737Sambrisko return (error); 3643158737Sambrisko printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid); 3644158737Sambrisko mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF, 3645158737Sambrisko M_WAITOK); 3646163398Sscottl mtx_lock(&sc->mfi_io_lock); 3647158737Sambrisko if (mfi_aen_entry != NULL) { 3648158737Sambrisko mfi_aen_entry->p = curproc; 3649158737Sambrisko TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry, 3650158737Sambrisko aen_link); 3651158737Sambrisko } 3652158737Sambrisko error = mfi_aen_register(sc, l_aen.laen_seq_num, 3653158737Sambrisko l_aen.laen_class_locale); 3654158737Sambrisko 3655158737Sambrisko if (error != 0) { 3656158737Sambrisko TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 3657158737Sambrisko aen_link); 3658158737Sambrisko free(mfi_aen_entry, M_MFIBUF); 3659158737Sambrisko } 3660163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3661158737Sambrisko 3662158737Sambrisko return (error); 3663158737Sambrisko default: 3664158737Sambrisko device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); 3665158737Sambrisko error = ENOENT; 3666158737Sambrisko break; 3667158737Sambrisko } 3668158737Sambrisko 3669158737Sambrisko return (error); 3670158737Sambrisko} 3671158737Sambrisko 3672158737Sambriskostatic int 3673158737Sambriskomfi_poll(struct cdev *dev, int poll_events, struct thread *td) 3674158737Sambrisko{ 3675158737Sambrisko struct mfi_softc *sc; 3676158737Sambrisko int revents = 0; 3677158737Sambrisko 3678158737Sambrisko sc = dev->si_drv1; 3679158737Sambrisko 3680158737Sambrisko if (poll_events & (POLLIN | POLLRDNORM)) { 3681163398Sscottl if (sc->mfi_aen_triggered != 0) { 3682158737Sambrisko revents |= poll_events & (POLLIN | POLLRDNORM); 3683163398Sscottl sc->mfi_aen_triggered = 0; 3684163398Sscottl } 3685158737Sambrisko if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) { 3686158737Sambrisko revents |= POLLERR; 3687158737Sambrisko } 3688158737Sambrisko } 3689158737Sambrisko 3690158737Sambrisko if (revents == 0) { 3691158737Sambrisko if (poll_events & (POLLIN | POLLRDNORM)) { 3692158737Sambrisko sc->mfi_poll_waiting = 1; 3693158737Sambrisko selrecord(td, &sc->mfi_select); 3694158737Sambrisko } 3695158737Sambrisko } 3696158737Sambrisko 3697158737Sambrisko return revents; 3698158737Sambrisko} 3699162619Sscottl 3700162619Sscottlstatic void 3701163398Sscottlmfi_dump_all(void) 3702163398Sscottl{ 3703163398Sscottl struct mfi_softc *sc; 3704163398Sscottl struct mfi_command *cm; 3705163398Sscottl devclass_t dc; 3706163398Sscottl time_t deadline; 3707163398Sscottl int timedout; 3708163398Sscottl int i; 3709163398Sscottl 3710163398Sscottl dc = devclass_find("mfi"); 3711163398Sscottl if (dc == NULL) { 3712163398Sscottl printf("No mfi dev class\n"); 3713163398Sscottl return; 3714163398Sscottl } 3715163398Sscottl 3716163398Sscottl for (i = 0; ; i++) { 3717163398Sscottl sc = devclass_get_softc(dc, i); 3718163398Sscottl if (sc == NULL) 3719163398Sscottl break; 3720163398Sscottl device_printf(sc->mfi_dev, "Dumping\n\n"); 3721163398Sscottl timedout = 0; 3722251406Ssmh deadline = time_uptime - mfi_cmd_timeout; 3723163398Sscottl mtx_lock(&sc->mfi_io_lock); 3724163398Sscottl TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) { 3725250496Ssmh if (cm->cm_timestamp <= deadline) { 3726163398Sscottl device_printf(sc->mfi_dev, 3727234429Sambrisko "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 3728234429Sambrisko cm, (int)(time_uptime - cm->cm_timestamp)); 3729163398Sscottl MFI_PRINT_CMD(cm); 3730163398Sscottl timedout++; 3731163398Sscottl } 3732163398Sscottl } 3733163398Sscottl 3734163398Sscottl#if 0 3735163398Sscottl if (timedout) 3736250496Ssmh MFI_DUMP_CMDS(sc); 3737163398Sscottl#endif 3738163398Sscottl 3739163398Sscottl mtx_unlock(&sc->mfi_io_lock); 3740163398Sscottl } 3741163398Sscottl 3742163398Sscottl return; 3743163398Sscottl} 3744163398Sscottl 3745163398Sscottlstatic void 3746162619Sscottlmfi_timeout(void *data) 3747162619Sscottl{ 3748162619Sscottl struct mfi_softc *sc = (struct mfi_softc *)data; 3749250496Ssmh struct mfi_command *cm, *tmp; 3750162619Sscottl time_t deadline; 3751162619Sscottl int timedout = 0; 3752162619Sscottl 3753251406Ssmh deadline = time_uptime - mfi_cmd_timeout; 3754234429Sambrisko if (sc->adpreset == 0) { 3755234429Sambrisko if (!mfi_tbolt_reset(sc)) { 3756251406Ssmh callout_reset(&sc->mfi_watchdog_callout, 3757251406Ssmh mfi_cmd_timeout * hz, mfi_timeout, sc); 3758234429Sambrisko return; 3759234429Sambrisko } 3760234429Sambrisko } 3761162619Sscottl mtx_lock(&sc->mfi_io_lock); 3762250496Ssmh TAILQ_FOREACH_SAFE(cm, &sc->mfi_busy, cm_link, tmp) { 3763235135Sambrisko if (sc->mfi_aen_cm == cm || sc->mfi_map_sync_cm == cm) 3764162688Sscottl continue; 3765250496Ssmh if (cm->cm_timestamp <= deadline) { 3766234429Sambrisko if (sc->adpreset != 0 && sc->issuepend_done == 0) { 3767234429Sambrisko cm->cm_timestamp = time_uptime; 3768234429Sambrisko } else { 3769234429Sambrisko device_printf(sc->mfi_dev, 3770234429Sambrisko "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 3771234429Sambrisko cm, (int)(time_uptime - cm->cm_timestamp) 3772234429Sambrisko ); 3773234429Sambrisko MFI_PRINT_CMD(cm); 3774234429Sambrisko MFI_VALIDATE_CMD(sc, cm); 3775250496Ssmh /* 3776252554Ssmh * While commands can get stuck forever we do 3777252554Ssmh * not fail them as there is no way to tell if 3778252554Ssmh * the controller has actually processed them 3779252554Ssmh * or not. 3780252554Ssmh * 3781252554Ssmh * In addition its very likely that force 3782252554Ssmh * failing a command here would cause a panic 3783252554Ssmh * e.g. in UFS. 3784250496Ssmh */ 3785234429Sambrisko timedout++; 3786234429Sambrisko } 3787162619Sscottl } 3788162619Sscottl } 3789162619Sscottl 3790162619Sscottl#if 0 3791162619Sscottl if (timedout) 3792250496Ssmh MFI_DUMP_CMDS(sc); 3793162619Sscottl#endif 3794162619Sscottl 3795162619Sscottl mtx_unlock(&sc->mfi_io_lock); 3796162619Sscottl 3797251406Ssmh callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz, 3798162619Sscottl mfi_timeout, sc); 3799162619Sscottl 3800163398Sscottl if (0) 3801163398Sscottl mfi_dump_all(); 3802162619Sscottl return; 3803162619Sscottl} 3804