mfi.c revision 240962
1254721Semaste/*- 2254721Semaste * Copyright (c) 2006 IronPort Systems 3254721Semaste * All rights reserved. 4254721Semaste * 5254721Semaste * Redistribution and use in source and binary forms, with or without 6254721Semaste * modification, are permitted provided that the following conditions 7254721Semaste * are met: 8254721Semaste * 1. Redistributions of source code must retain the above copyright 9254721Semaste * notice, this list of conditions and the following disclaimer. 10254721Semaste * 2. Redistributions in binary form must reproduce the above copyright 11254721Semaste * notice, this list of conditions and the following disclaimer in the 12254721Semaste * documentation and/or other materials provided with the distribution. 13263367Semaste * 14263367Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15263367Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16263363Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17263363Semaste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18254721Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19263363Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20254721Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21263363Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22254721Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23263363Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24263363Semaste * SUCH DAMAGE. 25263363Semaste */ 26269024Semaste/*- 27263363Semaste * Copyright (c) 2007 LSI Corp. 28263363Semaste * Copyright (c) 2007 Rajesh Prabhakaran. 29263363Semaste * All rights reserved. 30263363Semaste * 31263363Semaste * Redistribution and use in source and binary forms, with or without 32263363Semaste * modification, are permitted provided that the following conditions 33263363Semaste * are met: 34269024Semaste * 1. Redistributions of source code must retain the above copyright 35263363Semaste * notice, this list of conditions and the following disclaimer. 36263363Semaste * 2. Redistributions in binary form must reproduce the above copyright 37269024Semaste * notice, this list of conditions and the following disclaimer in the 38269024Semaste * documentation and/or other materials provided with the distribution. 39269024Semaste * 40269024Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 41269024Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42269024Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 43269024Semaste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 44269024Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 45269024Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 46269024Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47269024Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 48269024Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 49269024Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 50269024Semaste * SUCH DAMAGE. 51269024Semaste */ 52269024Semaste 53269024Semaste#include <sys/cdefs.h> 54269024Semaste__FBSDID("$FreeBSD: head/sys/dev/mfi/mfi.c 240962 2012-09-26 14:14:06Z jhb $"); 55269024Semaste 56269024Semaste#include "opt_compat.h" 57269024Semaste#include "opt_mfi.h" 58269024Semaste 59269024Semaste#include <sys/param.h> 60263363Semaste#include <sys/systm.h> 61263363Semaste#include <sys/sysctl.h> 62263363Semaste#include <sys/malloc.h> 63263363Semaste#include <sys/kernel.h> 64263363Semaste#include <sys/poll.h> 65263363Semaste#include <sys/selinfo.h> 66263363Semaste#include <sys/bus.h> 67263363Semaste#include <sys/conf.h> 68263363Semaste#include <sys/eventhandler.h> 69263363Semaste#include <sys/rman.h> 70263363Semaste#include <sys/bus_dma.h> 71263363Semaste#include <sys/bio.h> 72263363Semaste#include <sys/ioccom.h> 73263363Semaste#include <sys/uio.h> 74263363Semaste#include <sys/proc.h> 75263363Semaste#include <sys/signalvar.h> 76263363Semaste#include <sys/sysent.h> 77263363Semaste#include <sys/taskqueue.h> 78263363Semaste 79263363Semaste#include <machine/bus.h> 80263363Semaste#include <machine/resource.h> 81263363Semaste 82263363Semaste#include <dev/mfi/mfireg.h> 83263363Semaste#include <dev/mfi/mfi_ioctl.h> 84263363Semaste#include <dev/mfi/mfivar.h> 85263363Semaste#include <sys/interrupt.h> 86263363Semaste#include <sys/priority.h> 87263363Semaste 88263363Semastestatic int mfi_alloc_commands(struct mfi_softc *); 89263363Semastestatic int mfi_comms_init(struct mfi_softc *); 90263363Semastestatic int mfi_get_controller_info(struct mfi_softc *); 91263363Semastestatic int mfi_get_log_state(struct mfi_softc *, 92263363Semaste struct mfi_evt_log_state **); 93263363Semastestatic int mfi_parse_entries(struct mfi_softc *, int, int); 94263363Semastestatic void mfi_data_cb(void *, bus_dma_segment_t *, int, int); 95263363Semastestatic void mfi_startup(void *arg); 96263363Semastestatic void mfi_intr(void *arg); 97263363Semastestatic void mfi_ldprobe(struct mfi_softc *sc); 98263363Semastestatic void mfi_syspdprobe(struct mfi_softc *sc); 99263363Semastestatic void mfi_handle_evt(void *context, int pending); 100263363Semastestatic int mfi_aen_register(struct mfi_softc *sc, int seq, int locale); 101263363Semastestatic void mfi_aen_complete(struct mfi_command *); 102263363Semastestatic int mfi_add_ld(struct mfi_softc *sc, int); 103263363Semastestatic void mfi_add_ld_complete(struct mfi_command *); 104263363Semastestatic int mfi_add_sys_pd(struct mfi_softc *sc, int); 105263363Semastestatic void mfi_add_sys_pd_complete(struct mfi_command *); 106263363Semastestatic struct mfi_command * mfi_bio_command(struct mfi_softc *); 107263363Semastestatic void mfi_bio_complete(struct mfi_command *); 108263363Semastestatic struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*); 109263363Semastestatic struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*); 110263363Semastestatic int mfi_send_frame(struct mfi_softc *, struct mfi_command *); 111263363Semastestatic int mfi_abort(struct mfi_softc *, struct mfi_command *); 112263363Semastestatic int mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, struct thread *); 113263363Semastestatic void mfi_timeout(void *); 114263363Semastestatic int mfi_user_command(struct mfi_softc *, 115263363Semaste struct mfi_ioc_passthru *); 116263363Semastestatic void mfi_enable_intr_xscale(struct mfi_softc *sc); 117263363Semastestatic void mfi_enable_intr_ppc(struct mfi_softc *sc); 118263363Semastestatic int32_t mfi_read_fw_status_xscale(struct mfi_softc *sc); 119263363Semastestatic int32_t mfi_read_fw_status_ppc(struct mfi_softc *sc); 120263363Semastestatic int mfi_check_clear_intr_xscale(struct mfi_softc *sc); 121263363Semastestatic int mfi_check_clear_intr_ppc(struct mfi_softc *sc); 122263363Semastestatic void mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, 123263363Semaste uint32_t frame_cnt); 124263363Semastestatic void mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, 125263363Semaste uint32_t frame_cnt); 126263363Semastestatic int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode); 127263363Semastestatic void mfi_config_unlock(struct mfi_softc *sc, int locked); 128263363Semastestatic int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm); 129263363Semastestatic void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm); 130263363Semastestatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm); 131263363Semaste 132263363SemasteSYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters"); 133263363Semastestatic int mfi_event_locale = MFI_EVT_LOCALE_ALL; 134263363SemasteTUNABLE_INT("hw.mfi.event_locale", &mfi_event_locale); 135263363SemasteSYSCTL_INT(_hw_mfi, OID_AUTO, event_locale, CTLFLAG_RW, &mfi_event_locale, 136263363Semaste 0, "event message locale"); 137263363Semaste 138263363Semastestatic int mfi_event_class = MFI_EVT_CLASS_INFO; 139263363SemasteTUNABLE_INT("hw.mfi.event_class", &mfi_event_class); 140263363SemasteSYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RW, &mfi_event_class, 141263363Semaste 0, "event message class"); 142263363Semaste 143263363Semastestatic int mfi_max_cmds = 128; 144263363SemasteTUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds); 145263363SemasteSYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RD, &mfi_max_cmds, 146263363Semaste 0, "Max commands"); 147263363Semaste 148263363Semastestatic int mfi_detect_jbod_change = 1; 149263363SemasteTUNABLE_INT("hw.mfi.detect_jbod_change", &mfi_detect_jbod_change); 150263363SemasteSYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RW, 151263363Semaste &mfi_detect_jbod_change, 0, "Detect a change to a JBOD"); 152263363Semaste 153263363Semaste/* Management interface */ 154263363Semastestatic d_open_t mfi_open; 155263363Semastestatic d_close_t mfi_close; 156263363Semastestatic d_ioctl_t mfi_ioctl; 157263363Semastestatic d_poll_t mfi_poll; 158263363Semaste 159263363Semastestatic struct cdevsw mfi_cdevsw = { 160263363Semaste .d_version = D_VERSION, 161263363Semaste .d_flags = 0, 162263363Semaste .d_open = mfi_open, 163263363Semaste .d_close = mfi_close, 164263363Semaste .d_ioctl = mfi_ioctl, 165263363Semaste .d_poll = mfi_poll, 166263363Semaste .d_name = "mfi", 167263363Semaste}; 168263363Semaste 169263363SemasteMALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver"); 170263363Semaste 171263363Semaste#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH 172263363Semastestruct mfi_skinny_dma_info mfi_skinny; 173263363Semaste 174263363Semastestatic void 175263363Semastemfi_enable_intr_xscale(struct mfi_softc *sc) 176263363Semaste{ 177263363Semaste MFI_WRITE4(sc, MFI_OMSK, 0x01); 178263363Semaste} 179263363Semaste 180263363Semastestatic void 181263363Semastemfi_enable_intr_ppc(struct mfi_softc *sc) 182263363Semaste{ 183263363Semaste if (sc->mfi_flags & MFI_FLAGS_1078) { 184263363Semaste MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF); 185263363Semaste MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM); 186263363Semaste } 187263363Semaste else if (sc->mfi_flags & MFI_FLAGS_GEN2) { 188263363Semaste MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF); 189263363Semaste MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM); 190263363Semaste } 191263363Semaste else if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 192263363Semaste MFI_WRITE4(sc, MFI_OMSK, ~0x00000001); 193263363Semaste } 194263363Semaste} 195263363Semaste 196263363Semastestatic int32_t 197263363Semastemfi_read_fw_status_xscale(struct mfi_softc *sc) 198263363Semaste{ 199263363Semaste return MFI_READ4(sc, MFI_OMSG0); 200263363Semaste} 201263363Semaste 202263363Semastestatic int32_t 203263363Semastemfi_read_fw_status_ppc(struct mfi_softc *sc) 204263363Semaste{ 205263363Semaste return MFI_READ4(sc, MFI_OSP0); 206263363Semaste} 207263363Semaste 208263363Semastestatic int 209263363Semastemfi_check_clear_intr_xscale(struct mfi_softc *sc) 210263363Semaste{ 211263363Semaste int32_t status; 212263363Semaste 213263363Semaste status = MFI_READ4(sc, MFI_OSTS); 214263363Semaste if ((status & MFI_OSTS_INTR_VALID) == 0) 215263363Semaste return 1; 216263363Semaste 217263363Semaste MFI_WRITE4(sc, MFI_OSTS, status); 218263363Semaste return 0; 219263363Semaste} 220263363Semaste 221263363Semastestatic int 222263363Semastemfi_check_clear_intr_ppc(struct mfi_softc *sc) 223263363Semaste{ 224263363Semaste int32_t status; 225263363Semaste 226263363Semaste status = MFI_READ4(sc, MFI_OSTS); 227263363Semaste if (sc->mfi_flags & MFI_FLAGS_1078) { 228263363Semaste if (!(status & MFI_1078_RM)) { 229263363Semaste return 1; 230263363Semaste } 231263363Semaste } 232263363Semaste else if (sc->mfi_flags & MFI_FLAGS_GEN2) { 233263363Semaste if (!(status & MFI_GEN2_RM)) { 234263363Semaste return 1; 235263363Semaste } 236263363Semaste } 237263363Semaste else if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 238263363Semaste if (!(status & MFI_SKINNY_RM)) { 239263363Semaste return 1; 240263363Semaste } 241263363Semaste } 242263363Semaste if (sc->mfi_flags & MFI_FLAGS_SKINNY) 243263363Semaste MFI_WRITE4(sc, MFI_OSTS, status); 244263363Semaste else 245263363Semaste MFI_WRITE4(sc, MFI_ODCR0, status); 246263363Semaste return 0; 247263363Semaste} 248263363Semaste 249263363Semastestatic void 250263363Semastemfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt) 251263363Semaste{ 252263363Semaste MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt); 253263363Semaste} 254263363Semaste 255263363Semastestatic void 256263363Semastemfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt) 257263363Semaste{ 258263363Semaste if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 259263363Semaste MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt <<1)|1 ); 260263363Semaste MFI_WRITE4(sc, MFI_IQPH, 0x00000000); 261263363Semaste } else { 262263363Semaste MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt <<1)|1 ); 263263363Semaste } 264263363Semaste} 265263363Semaste 266263363Semasteint 267263363Semastemfi_transition_firmware(struct mfi_softc *sc) 268263363Semaste{ 269263363Semaste uint32_t fw_state, cur_state; 270263363Semaste int max_wait, i; 271263363Semaste uint32_t cur_abs_reg_val = 0; 272263363Semaste uint32_t prev_abs_reg_val = 0; 273263363Semaste 274263363Semaste cur_abs_reg_val = sc->mfi_read_fw_status(sc); 275263363Semaste fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK; 276263363Semaste while (fw_state != MFI_FWSTATE_READY) { 277263363Semaste if (bootverbose) 278263363Semaste device_printf(sc->mfi_dev, "Waiting for firmware to " 279263363Semaste "become ready\n"); 280263363Semaste cur_state = fw_state; 281263363Semaste switch (fw_state) { 282263363Semaste case MFI_FWSTATE_FAULT: 283263363Semaste device_printf(sc->mfi_dev, "Firmware fault\n"); 284263363Semaste return (ENXIO); 285263363Semaste case MFI_FWSTATE_WAIT_HANDSHAKE: 286263363Semaste if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 287263363Semaste MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE); 288263363Semaste else 289263363Semaste MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE); 290263363Semaste max_wait = MFI_RESET_WAIT_TIME; 291263363Semaste break; 292263363Semaste case MFI_FWSTATE_OPERATIONAL: 293263363Semaste if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 294263363Semaste MFI_WRITE4(sc, MFI_SKINNY_IDB, 7); 295263363Semaste else 296263363Semaste MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY); 297263363Semaste max_wait = MFI_RESET_WAIT_TIME; 298263363Semaste break; 299263363Semaste case MFI_FWSTATE_UNDEFINED: 300263363Semaste case MFI_FWSTATE_BB_INIT: 301263363Semaste max_wait = MFI_RESET_WAIT_TIME; 302263363Semaste break; 303263363Semaste case MFI_FWSTATE_FW_INIT_2: 304263363Semaste max_wait = MFI_RESET_WAIT_TIME; 305263363Semaste break; 306263363Semaste case MFI_FWSTATE_FW_INIT: 307263363Semaste case MFI_FWSTATE_FLUSH_CACHE: 308263363Semaste max_wait = MFI_RESET_WAIT_TIME; 309263363Semaste break; 310263363Semaste case MFI_FWSTATE_DEVICE_SCAN: 311263363Semaste max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */ 312263363Semaste prev_abs_reg_val = cur_abs_reg_val; 313263363Semaste break; 314263363Semaste case MFI_FWSTATE_BOOT_MESSAGE_PENDING: 315263363Semaste if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT) 316263363Semaste MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG); 317263363Semaste else 318263363Semaste MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG); 319263363Semaste max_wait = MFI_RESET_WAIT_TIME; 320263363Semaste break; 321263363Semaste default: 322263363Semaste device_printf(sc->mfi_dev, "Unknown firmware state %#x\n", 323263363Semaste fw_state); 324263363Semaste return (ENXIO); 325263363Semaste } 326263363Semaste for (i = 0; i < (max_wait * 10); i++) { 327263363Semaste cur_abs_reg_val = sc->mfi_read_fw_status(sc); 328263363Semaste fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK; 329263363Semaste if (fw_state == cur_state) 330263363Semaste DELAY(100000); 331263363Semaste else 332263363Semaste break; 333263363Semaste } 334263363Semaste if (fw_state == MFI_FWSTATE_DEVICE_SCAN) { 335263363Semaste /* Check the device scanning progress */ 336263363Semaste if (prev_abs_reg_val != cur_abs_reg_val) { 337263363Semaste continue; 338263363Semaste } 339263363Semaste } 340263363Semaste if (fw_state == cur_state) { 341263363Semaste device_printf(sc->mfi_dev, "Firmware stuck in state " 342263363Semaste "%#x\n", fw_state); 343263363Semaste return (ENXIO); 344263363Semaste } 345263363Semaste } 346263363Semaste return (0); 347263363Semaste} 348263363Semaste 349263363Semastestatic void 350263363Semastemfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 351263363Semaste{ 352263363Semaste bus_addr_t *addr; 353263363Semaste 354263363Semaste addr = arg; 355263363Semaste *addr = segs[0].ds_addr; 356263363Semaste} 357263363Semaste 358263363Semaste 359263363Semasteint 360263363Semastemfi_attach(struct mfi_softc *sc) 361263363Semaste{ 362263363Semaste uint32_t status; 363263363Semaste int error, commsz, framessz, sensesz; 364263363Semaste int frames, unit, max_fw_sge; 365263363Semaste uint32_t tb_mem_size = 0; 366263363Semaste 367263363Semaste if (sc == NULL) 368263363Semaste return EINVAL; 369263363Semaste 370263363Semaste device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n", 371263363Semaste MEGASAS_VERSION); 372263363Semaste 373263363Semaste mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF); 374263363Semaste sx_init(&sc->mfi_config_lock, "MFI config"); 375263363Semaste TAILQ_INIT(&sc->mfi_ld_tqh); 376263363Semaste TAILQ_INIT(&sc->mfi_syspd_tqh); 377263363Semaste TAILQ_INIT(&sc->mfi_evt_queue); 378263363Semaste TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc); 379263363Semaste TASK_INIT(&sc->mfi_map_sync_task, 0, mfi_handle_map_sync, sc); 380263363Semaste TAILQ_INIT(&sc->mfi_aen_pids); 381263363Semaste TAILQ_INIT(&sc->mfi_cam_ccbq); 382263363Semaste 383263363Semaste mfi_initq_free(sc); 384263363Semaste mfi_initq_ready(sc); 385263363Semaste mfi_initq_busy(sc); 386263363Semaste mfi_initq_bio(sc); 387263363Semaste 388263363Semaste sc->adpreset = 0; 389263363Semaste sc->last_seq_num = 0; 390263363Semaste sc->disableOnlineCtrlReset = 1; 391263363Semaste sc->issuepend_done = 1; 392263363Semaste sc->hw_crit_error = 0; 393263363Semaste 394263363Semaste if (sc->mfi_flags & MFI_FLAGS_1064R) { 395263363Semaste sc->mfi_enable_intr = mfi_enable_intr_xscale; 396263363Semaste sc->mfi_read_fw_status = mfi_read_fw_status_xscale; 397263363Semaste sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale; 398263363Semaste sc->mfi_issue_cmd = mfi_issue_cmd_xscale; 399263363Semaste } else if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 400263363Semaste sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc; 401263363Semaste sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc; 402263363Semaste sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc; 403263363Semaste sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc; 404263363Semaste sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc; 405263363Semaste sc->mfi_adp_reset = mfi_tbolt_adp_reset; 406263363Semaste sc->mfi_tbolt = 1; 407263363Semaste TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh); 408263363Semaste } else { 409263363Semaste sc->mfi_enable_intr = mfi_enable_intr_ppc; 410263363Semaste sc->mfi_read_fw_status = mfi_read_fw_status_ppc; 411263363Semaste sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc; 412263363Semaste sc->mfi_issue_cmd = mfi_issue_cmd_ppc; 413263363Semaste } 414263363Semaste 415263363Semaste 416263363Semaste /* Before we get too far, see if the firmware is working */ 417263363Semaste if ((error = mfi_transition_firmware(sc)) != 0) { 418263363Semaste device_printf(sc->mfi_dev, "Firmware not in READY state, " 419263363Semaste "error %d\n", error); 420263363Semaste return (ENXIO); 421263363Semaste } 422263363Semaste 423263363Semaste /* Start: LSIP200113393 */ 424263363Semaste if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 425263363Semaste 1, 0, /* algnmnt, boundary */ 426263363Semaste BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 427263363Semaste BUS_SPACE_MAXADDR, /* highaddr */ 428263363Semaste NULL, NULL, /* filter, filterarg */ 429263363Semaste MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsize */ 430263363Semaste 1, /* msegments */ 431263363Semaste MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsegsize */ 432263363Semaste 0, /* flags */ 433263363Semaste NULL, NULL, /* lockfunc, lockarg */ 434263363Semaste &sc->verbuf_h_dmat)) { 435263363Semaste device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n"); 436263363Semaste return (ENOMEM); 437263363Semaste } 438263363Semaste if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf, 439263363Semaste BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) { 440263363Semaste device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n"); 441263363Semaste return (ENOMEM); 442263363Semaste } 443263363Semaste bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t)); 444263363Semaste bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap, 445263363Semaste sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t), 446263363Semaste mfi_addr_cb, &sc->verbuf_h_busaddr, 0); 447263363Semaste /* End: LSIP200113393 */ 448263363Semaste 449263363Semaste /* 450263363Semaste * Get information needed for sizing the contiguous memory for the 451263363Semaste * frame pool. Size down the sgl parameter since we know that 452263363Semaste * we will never need more than what's required for MAXPHYS. 453263363Semaste * It would be nice if these constants were available at runtime 454263363Semaste * instead of compile time. 455263363Semaste */ 456263363Semaste status = sc->mfi_read_fw_status(sc); 457263363Semaste sc->mfi_max_fw_cmds = status & MFI_FWSTATE_MAXCMD_MASK; 458263363Semaste max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16; 459263363Semaste sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1)); 460263363Semaste 461263363Semaste /* ThunderBolt Support get the contiguous memory */ 462263363Semaste 463263363Semaste if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 464263363Semaste mfi_tbolt_init_globals(sc); 465263363Semaste device_printf(sc->mfi_dev, "MaxCmd = %x MaxSgl = %x state = %x \n", 466263363Semaste sc->mfi_max_fw_cmds, sc->mfi_max_sge, status); 467263363Semaste tb_mem_size = mfi_tbolt_get_memory_requirement(sc); 468263363Semaste 469263363Semaste if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 470263363Semaste 1, 0, /* algnmnt, boundary */ 471263363Semaste BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 472263363Semaste BUS_SPACE_MAXADDR, /* highaddr */ 473263363Semaste NULL, NULL, /* filter, filterarg */ 474263363Semaste tb_mem_size, /* maxsize */ 475263363Semaste 1, /* msegments */ 476263363Semaste tb_mem_size, /* maxsegsize */ 477263363Semaste 0, /* flags */ 478263363Semaste NULL, NULL, /* lockfunc, lockarg */ 479263363Semaste &sc->mfi_tb_dmat)) { 480263363Semaste device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n"); 481263363Semaste return (ENOMEM); 482263363Semaste } 483263363Semaste if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool, 484263363Semaste BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) { 485263363Semaste device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 486263363Semaste return (ENOMEM); 487263363Semaste } 488263363Semaste bzero(sc->request_message_pool, tb_mem_size); 489263363Semaste bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap, 490263363Semaste sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0); 491263363Semaste 492263363Semaste /* For ThunderBolt memory init */ 493263363Semaste if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 494263363Semaste 0x100, 0, /* alignmnt, boundary */ 495263363Semaste BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 496263363Semaste BUS_SPACE_MAXADDR, /* highaddr */ 497263363Semaste NULL, NULL, /* filter, filterarg */ 498263363Semaste MFI_FRAME_SIZE, /* maxsize */ 499263363Semaste 1, /* msegments */ 500263363Semaste MFI_FRAME_SIZE, /* maxsegsize */ 501263363Semaste 0, /* flags */ 502263363Semaste NULL, NULL, /* lockfunc, lockarg */ 503263363Semaste &sc->mfi_tb_init_dmat)) { 504263363Semaste device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n"); 505263363Semaste return (ENOMEM); 506263363Semaste } 507263363Semaste if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init, 508263363Semaste BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) { 509263363Semaste device_printf(sc->mfi_dev, "Cannot allocate init memory\n"); 510263363Semaste return (ENOMEM); 511263363Semaste } 512263363Semaste bzero(sc->mfi_tb_init, MFI_FRAME_SIZE); 513263363Semaste bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap, 514263363Semaste sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb, 515263363Semaste &sc->mfi_tb_init_busaddr, 0); 516263363Semaste if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool, 517263363Semaste tb_mem_size)) { 518263363Semaste device_printf(sc->mfi_dev, 519263363Semaste "Thunderbolt pool preparation error\n"); 520263363Semaste return 0; 521263363Semaste } 522263363Semaste 523263363Semaste /* 524263363Semaste Allocate DMA memory mapping for MPI2 IOC Init descriptor, 525263363Semaste we are taking it diffrent from what we have allocated for Request 526263363Semaste and reply descriptors to avoid confusion later 527263363Semaste */ 528263363Semaste tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST); 529263363Semaste if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 530263363Semaste 1, 0, /* algnmnt, boundary */ 531263363Semaste BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 532263363Semaste BUS_SPACE_MAXADDR, /* highaddr */ 533263363Semaste NULL, NULL, /* filter, filterarg */ 534263363Semaste tb_mem_size, /* maxsize */ 535263363Semaste 1, /* msegments */ 536263363Semaste tb_mem_size, /* maxsegsize */ 537263363Semaste 0, /* flags */ 538263363Semaste NULL, NULL, /* lockfunc, lockarg */ 539263363Semaste &sc->mfi_tb_ioc_init_dmat)) { 540263363Semaste device_printf(sc->mfi_dev, 541263363Semaste "Cannot allocate comms DMA tag\n"); 542263363Semaste return (ENOMEM); 543263363Semaste } 544263363Semaste if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat, 545263363Semaste (void **)&sc->mfi_tb_ioc_init_desc, 546263363Semaste BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) { 547263363Semaste device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 548263363Semaste return (ENOMEM); 549263363Semaste } 550263363Semaste bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size); 551263363Semaste bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap, 552263363Semaste sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb, 553263363Semaste &sc->mfi_tb_ioc_init_busaddr, 0); 554263363Semaste } 555263363Semaste /* 556263363Semaste * Create the dma tag for data buffers. Used both for block I/O 557263363Semaste * and for various internal data queries. 558263363Semaste */ 559263363Semaste if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 560263363Semaste 1, 0, /* algnmnt, boundary */ 561263363Semaste BUS_SPACE_MAXADDR, /* lowaddr */ 562263363Semaste BUS_SPACE_MAXADDR, /* highaddr */ 563263363Semaste NULL, NULL, /* filter, filterarg */ 564263363Semaste BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 565263363Semaste sc->mfi_max_sge, /* nsegments */ 566263363Semaste BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 567263363Semaste BUS_DMA_ALLOCNOW, /* flags */ 568263363Semaste busdma_lock_mutex, /* lockfunc */ 569263363Semaste &sc->mfi_io_lock, /* lockfuncarg */ 570263363Semaste &sc->mfi_buffer_dmat)) { 571263363Semaste device_printf(sc->mfi_dev, "Cannot allocate buffer DMA tag\n"); 572263363Semaste return (ENOMEM); 573263363Semaste } 574263363Semaste 575263363Semaste /* 576263363Semaste * Allocate DMA memory for the comms queues. Keep it under 4GB for 577263363Semaste * efficiency. The mfi_hwcomms struct includes space for 1 reply queue 578269024Semaste * entry, so the calculated size here will be will be 1 more than 579269024Semaste * mfi_max_fw_cmds. This is apparently a requirement of the hardware. 580263363Semaste */ 581263363Semaste commsz = (sizeof(uint32_t) * sc->mfi_max_fw_cmds) + 582263363Semaste sizeof(struct mfi_hwcomms); 583263363Semaste if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 584263363Semaste 1, 0, /* algnmnt, boundary */ 585263363Semaste BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 586263363Semaste BUS_SPACE_MAXADDR, /* highaddr */ 587263363Semaste NULL, NULL, /* filter, filterarg */ 588263363Semaste commsz, /* maxsize */ 589263363Semaste 1, /* msegments */ 590263363Semaste commsz, /* maxsegsize */ 591263363Semaste 0, /* flags */ 592263363Semaste NULL, NULL, /* lockfunc, lockarg */ 593263363Semaste &sc->mfi_comms_dmat)) { 594263363Semaste device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n"); 595263363Semaste return (ENOMEM); 596263363Semaste } 597263363Semaste if (bus_dmamem_alloc(sc->mfi_comms_dmat, (void **)&sc->mfi_comms, 598263363Semaste BUS_DMA_NOWAIT, &sc->mfi_comms_dmamap)) { 599263363Semaste device_printf(sc->mfi_dev, "Cannot allocate comms memory\n"); 600263363Semaste return (ENOMEM); 601263363Semaste } 602269024Semaste bzero(sc->mfi_comms, commsz); 603263363Semaste bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap, 604263363Semaste sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0); 605263363Semaste /* 606263363Semaste * Allocate DMA memory for the command frames. Keep them in the 607263363Semaste * lower 4GB for efficiency. Calculate the size of the commands at 608263363Semaste * the same time; each command is one 64 byte frame plus a set of 609263363Semaste * additional frames for holding sg lists or other data. 610263363Semaste * The assumption here is that the SG list will start at the second 611263363Semaste * frame and not use the unused bytes in the first frame. While this 612263363Semaste * isn't technically correct, it simplifies the calculation and allows 613263363Semaste * for command frames that might be larger than an mfi_io_frame. 614263363Semaste */ 615263363Semaste if (sizeof(bus_addr_t) == 8) { 616263363Semaste sc->mfi_sge_size = sizeof(struct mfi_sg64); 617263363Semaste sc->mfi_flags |= MFI_FLAGS_SG64; 618263363Semaste } else { 619263363Semaste sc->mfi_sge_size = sizeof(struct mfi_sg32); 620263363Semaste } 621263363Semaste if (sc->mfi_flags & MFI_FLAGS_SKINNY) 622263363Semaste sc->mfi_sge_size = sizeof(struct mfi_sg_skinny); 623263363Semaste frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2; 624263363Semaste sc->mfi_cmd_size = frames * MFI_FRAME_SIZE; 625263363Semaste framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds; 626263363Semaste if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 627263363Semaste 64, 0, /* algnmnt, boundary */ 628263363Semaste BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 629263363Semaste BUS_SPACE_MAXADDR, /* highaddr */ 630263363Semaste NULL, NULL, /* filter, filterarg */ 631263363Semaste framessz, /* maxsize */ 632263363Semaste 1, /* nsegments */ 633263363Semaste framessz, /* maxsegsize */ 634263363Semaste 0, /* flags */ 635263363Semaste NULL, NULL, /* lockfunc, lockarg */ 636263363Semaste &sc->mfi_frames_dmat)) { 637269024Semaste device_printf(sc->mfi_dev, "Cannot allocate frame DMA tag\n"); 638269024Semaste return (ENOMEM); 639263363Semaste } 640263363Semaste if (bus_dmamem_alloc(sc->mfi_frames_dmat, (void **)&sc->mfi_frames, 641263363Semaste BUS_DMA_NOWAIT, &sc->mfi_frames_dmamap)) { 642263363Semaste device_printf(sc->mfi_dev, "Cannot allocate frames memory\n"); 643263363Semaste return (ENOMEM); 644263363Semaste } 645263363Semaste bzero(sc->mfi_frames, framessz); 646263363Semaste bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap, 647263363Semaste sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0); 648263363Semaste /* 649263363Semaste * Allocate DMA memory for the frame sense data. Keep them in the 650263363Semaste * lower 4GB for efficiency 651263363Semaste */ 652263363Semaste sensesz = sc->mfi_max_fw_cmds * MFI_SENSE_LEN; 653263363Semaste if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 654263363Semaste 4, 0, /* algnmnt, boundary */ 655263363Semaste BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 656263363Semaste BUS_SPACE_MAXADDR, /* highaddr */ 657263363Semaste NULL, NULL, /* filter, filterarg */ 658263363Semaste sensesz, /* maxsize */ 659263363Semaste 1, /* nsegments */ 660263363Semaste sensesz, /* maxsegsize */ 661263363Semaste 0, /* flags */ 662263363Semaste NULL, NULL, /* lockfunc, lockarg */ 663269024Semaste &sc->mfi_sense_dmat)) { 664269024Semaste device_printf(sc->mfi_dev, "Cannot allocate sense DMA tag\n"); 665263363Semaste return (ENOMEM); 666263363Semaste } 667263363Semaste if (bus_dmamem_alloc(sc->mfi_sense_dmat, (void **)&sc->mfi_sense, 668263363Semaste BUS_DMA_NOWAIT, &sc->mfi_sense_dmamap)) { 669263363Semaste device_printf(sc->mfi_dev, "Cannot allocate sense memory\n"); 670263363Semaste return (ENOMEM); 671263363Semaste } 672263363Semaste bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap, 673263363Semaste sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0); 674263363Semaste if ((error = mfi_alloc_commands(sc)) != 0) 675263363Semaste return (error); 676263363Semaste 677263363Semaste /* Before moving the FW to operational state, check whether 678263363Semaste * hostmemory is required by the FW or not 679263363Semaste */ 680263363Semaste 681263363Semaste /* ThunderBolt MFI_IOC2 INIT */ 682263363Semaste if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 683263363Semaste sc->mfi_disable_intr(sc); 684263363Semaste if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) { 685263363Semaste device_printf(sc->mfi_dev, 686263363Semaste "TB Init has failed with error %d\n",error); 687263363Semaste return error; 688263363Semaste } 689269024Semaste 690269024Semaste if ((error = mfi_tbolt_alloc_cmd(sc)) != 0) 691263363Semaste return error; 692263363Semaste if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, 693263363Semaste INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc, 694263363Semaste &sc->mfi_intr)) { 695263363Semaste device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); 696263363Semaste return (EINVAL); 697263363Semaste } 698263363Semaste sc->mfi_enable_intr(sc); 699263363Semaste } else { 700263363Semaste if ((error = mfi_comms_init(sc)) != 0) 701263363Semaste return (error); 702263363Semaste 703263363Semaste if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, 704263363Semaste INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) { 705263363Semaste device_printf(sc->mfi_dev, "Cannot set up interrupt\n"); 706263363Semaste return (EINVAL); 707263363Semaste } 708263363Semaste sc->mfi_enable_intr(sc); 709263363Semaste } 710263363Semaste if ((error = mfi_get_controller_info(sc)) != 0) 711263363Semaste return (error); 712263363Semaste sc->disableOnlineCtrlReset = 0; 713263363Semaste 714263363Semaste /* Register a config hook to probe the bus for arrays */ 715269024Semaste sc->mfi_ich.ich_func = mfi_startup; 716269024Semaste sc->mfi_ich.ich_arg = sc; 717263363Semaste if (config_intrhook_establish(&sc->mfi_ich) != 0) { 718263363Semaste device_printf(sc->mfi_dev, "Cannot establish configuration " 719263363Semaste "hook\n"); 720263363Semaste return (EINVAL); 721263363Semaste } 722263363Semaste if ((error = mfi_aen_setup(sc, 0), 0) != 0) { 723263363Semaste mtx_unlock(&sc->mfi_io_lock); 724263363Semaste return (error); 725263363Semaste } 726263363Semaste 727263363Semaste /* 728263363Semaste * Register a shutdown handler. 729263363Semaste */ 730263363Semaste if ((sc->mfi_eh = EVENTHANDLER_REGISTER(shutdown_final, mfi_shutdown, 731263363Semaste sc, SHUTDOWN_PRI_DEFAULT)) == NULL) { 732263363Semaste device_printf(sc->mfi_dev, "Warning: shutdown event " 733263363Semaste "registration failed\n"); 734263363Semaste } 735263363Semaste 736263363Semaste /* 737263363Semaste * Create the control device for doing management 738263363Semaste */ 739263363Semaste unit = device_get_unit(sc->mfi_dev); 740263363Semaste sc->mfi_cdev = make_dev(&mfi_cdevsw, unit, UID_ROOT, GID_OPERATOR, 741263363Semaste 0640, "mfi%d", unit); 742263363Semaste if (unit == 0) 743263363Semaste make_dev_alias(sc->mfi_cdev, "megaraid_sas_ioctl_node"); 744263363Semaste if (sc->mfi_cdev != NULL) 745263363Semaste sc->mfi_cdev->si_drv1 = sc; 746263363Semaste SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev), 747263363Semaste SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), 748263363Semaste OID_AUTO, "delete_busy_volumes", CTLFLAG_RW, 749263363Semaste &sc->mfi_delete_busy_volumes, 0, "Allow removal of busy volumes"); 750263363Semaste SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev), 751263363Semaste SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), 752263363Semaste OID_AUTO, "keep_deleted_volumes", CTLFLAG_RW, 753269024Semaste &sc->mfi_keep_deleted_volumes, 0, 754269024Semaste "Don't detach the mfid device for a busy volume that is deleted"); 755263363Semaste 756263363Semaste device_add_child(sc->mfi_dev, "mfip", -1); 757263363Semaste bus_generic_attach(sc->mfi_dev); 758263363Semaste 759263363Semaste /* Start the timeout watchdog */ 760263363Semaste callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE); 761263363Semaste callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, 762263363Semaste mfi_timeout, sc); 763263363Semaste 764263363Semaste if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 765263363Semaste mfi_tbolt_sync_map_info(sc); 766263363Semaste } 767263363Semaste 768263363Semaste return (0); 769263363Semaste} 770263363Semaste 771263363Semastestatic int 772263363Semastemfi_alloc_commands(struct mfi_softc *sc) 773269024Semaste{ 774269024Semaste struct mfi_command *cm; 775263363Semaste int i, ncmds; 776263363Semaste 777263363Semaste /* 778263363Semaste * XXX Should we allocate all the commands up front, or allocate on 779263363Semaste * demand later like 'aac' does? 780263363Semaste */ 781263363Semaste ncmds = MIN(mfi_max_cmds, sc->mfi_max_fw_cmds); 782263363Semaste if (bootverbose) 783263363Semaste device_printf(sc->mfi_dev, "Max fw cmds= %d, sizing driver " 784263363Semaste "pool to %d\n", sc->mfi_max_fw_cmds, ncmds); 785263363Semaste 786263363Semaste sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF, 787263363Semaste M_WAITOK | M_ZERO); 788263363Semaste 789263363Semaste for (i = 0; i < ncmds; i++) { 790263363Semaste cm = &sc->mfi_commands[i]; 791263363Semaste cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_frames + 792263363Semaste sc->mfi_cmd_size * i); 793263363Semaste cm->cm_frame_busaddr = sc->mfi_frames_busaddr + 794263363Semaste sc->mfi_cmd_size * i; 795263363Semaste cm->cm_frame->header.context = i; 796263363Semaste cm->cm_sense = &sc->mfi_sense[i]; 797263363Semaste cm->cm_sense_busaddr= sc->mfi_sense_busaddr + MFI_SENSE_LEN * i; 798263363Semaste cm->cm_sc = sc; 799263363Semaste cm->cm_index = i; 800263363Semaste if (bus_dmamap_create(sc->mfi_buffer_dmat, 0, 801263363Semaste &cm->cm_dmamap) == 0) { 802263363Semaste mtx_lock(&sc->mfi_io_lock); 803263363Semaste mfi_release_command(cm); 804263363Semaste mtx_unlock(&sc->mfi_io_lock); 805263363Semaste } 806263363Semaste else 807263363Semaste break; 808263363Semaste sc->mfi_total_cmds++; 809263363Semaste } 810263363Semaste 811263363Semaste return (0); 812263363Semaste} 813263363Semaste 814263363Semastevoid 815263363Semastemfi_release_command(struct mfi_command *cm) 816263363Semaste{ 817263363Semaste struct mfi_frame_header *hdr; 818263363Semaste uint32_t *hdr_data; 819263363Semaste 820263363Semaste mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED); 821263363Semaste 822263363Semaste /* 823263363Semaste * Zero out the important fields of the frame, but make sure the 824263363Semaste * context field is preserved. For efficiency, handle the fields 825263363Semaste * as 32 bit words. Clear out the first S/G entry too for safety. 826263363Semaste */ 827263363Semaste hdr = &cm->cm_frame->header; 828263363Semaste if (cm->cm_data != NULL && hdr->sg_count) { 829263363Semaste cm->cm_sg->sg32[0].len = 0; 830263363Semaste cm->cm_sg->sg32[0].addr = 0; 831263363Semaste } 832263363Semaste 833263363Semaste hdr_data = (uint32_t *)cm->cm_frame; 834263363Semaste hdr_data[0] = 0; /* cmd, sense_len, cmd_status, scsi_status */ 835263363Semaste hdr_data[1] = 0; /* target_id, lun_id, cdb_len, sg_count */ 836263363Semaste hdr_data[4] = 0; /* flags, timeout */ 837263363Semaste hdr_data[5] = 0; /* data_len */ 838263363Semaste 839263363Semaste cm->cm_extra_frames = 0; 840263363Semaste cm->cm_flags = 0; 841263363Semaste cm->cm_complete = NULL; 842263363Semaste cm->cm_private = NULL; 843263363Semaste cm->cm_data = NULL; 844263363Semaste cm->cm_sg = 0; 845263363Semaste cm->cm_total_frame_size = 0; 846263363Semaste cm->retry_for_fw_reset = 0; 847263363Semaste 848263363Semaste mfi_enqueue_free(cm); 849263363Semaste} 850263363Semaste 851263363Semasteint 852263363Semastemfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, 853263363Semaste uint32_t opcode, void **bufp, size_t bufsize) 854263363Semaste{ 855263363Semaste struct mfi_command *cm; 856263363Semaste struct mfi_dcmd_frame *dcmd; 857263363Semaste void *buf = NULL; 858263363Semaste uint32_t context = 0; 859263363Semaste 860263363Semaste mtx_assert(&sc->mfi_io_lock, MA_OWNED); 861263363Semaste 862263363Semaste cm = mfi_dequeue_free(sc); 863263363Semaste if (cm == NULL) 864263363Semaste return (EBUSY); 865263363Semaste 866269024Semaste /* Zero out the MFI frame */ 867269024Semaste context = cm->cm_frame->header.context; 868263363Semaste bzero(cm->cm_frame, sizeof(union mfi_frame)); 869263363Semaste cm->cm_frame->header.context = context; 870263363Semaste 871263363Semaste if ((bufsize > 0) && (bufp != NULL)) { 872263363Semaste if (*bufp == NULL) { 873263363Semaste buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO); 874263363Semaste if (buf == NULL) { 875263363Semaste mfi_release_command(cm); 876263363Semaste return (ENOMEM); 877263363Semaste } 878263363Semaste *bufp = buf; 879263363Semaste } else { 880263363Semaste buf = *bufp; 881263363Semaste } 882263363Semaste } 883263363Semaste 884263363Semaste dcmd = &cm->cm_frame->dcmd; 885263363Semaste bzero(dcmd->mbox, MFI_MBOX_SIZE); 886263363Semaste dcmd->header.cmd = MFI_CMD_DCMD; 887263363Semaste dcmd->header.timeout = 0; 888263363Semaste dcmd->header.flags = 0; 889263363Semaste dcmd->header.data_len = bufsize; 890263363Semaste dcmd->header.scsi_status = 0; 891269024Semaste dcmd->opcode = opcode; 892269024Semaste cm->cm_sg = &dcmd->sgl; 893263363Semaste cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 894263363Semaste cm->cm_flags = 0; 895263363Semaste cm->cm_data = buf; 896263363Semaste cm->cm_private = buf; 897263363Semaste cm->cm_len = bufsize; 898263363Semaste 899263363Semaste *cmp = cm; 900263363Semaste if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL)) 901263363Semaste *bufp = buf; 902263363Semaste return (0); 903263363Semaste} 904263363Semaste 905263363Semastestatic int 906263363Semastemfi_comms_init(struct mfi_softc *sc) 907263363Semaste{ 908263363Semaste struct mfi_command *cm; 909263363Semaste struct mfi_init_frame *init; 910263363Semaste struct mfi_init_qinfo *qinfo; 911269024Semaste int error; 912269024Semaste uint32_t context = 0; 913263363Semaste 914263363Semaste mtx_lock(&sc->mfi_io_lock); 915263363Semaste if ((cm = mfi_dequeue_free(sc)) == NULL) 916263363Semaste return (EBUSY); 917263363Semaste 918263363Semaste /* Zero out the MFI frame */ 919263363Semaste context = cm->cm_frame->header.context; 920263363Semaste bzero(cm->cm_frame, sizeof(union mfi_frame)); 921263363Semaste cm->cm_frame->header.context = context; 922263363Semaste 923263363Semaste /* 924263363Semaste * Abuse the SG list area of the frame to hold the init_qinfo 925263363Semaste * object; 926263363Semaste */ 927263363Semaste init = &cm->cm_frame->init; 928263363Semaste qinfo = (struct mfi_init_qinfo *)((uintptr_t)init + MFI_FRAME_SIZE); 929263363Semaste 930263363Semaste bzero(qinfo, sizeof(struct mfi_init_qinfo)); 931263363Semaste qinfo->rq_entries = sc->mfi_max_fw_cmds + 1; 932263363Semaste qinfo->rq_addr_lo = sc->mfi_comms_busaddr + 933263363Semaste offsetof(struct mfi_hwcomms, hw_reply_q); 934269024Semaste qinfo->pi_addr_lo = sc->mfi_comms_busaddr + 935269024Semaste offsetof(struct mfi_hwcomms, hw_pi); 936263363Semaste qinfo->ci_addr_lo = sc->mfi_comms_busaddr + 937263363Semaste offsetof(struct mfi_hwcomms, hw_ci); 938263363Semaste 939263363Semaste init->header.cmd = MFI_CMD_INIT; 940263363Semaste init->header.data_len = sizeof(struct mfi_init_qinfo); 941263363Semaste init->qinfo_new_addr_lo = cm->cm_frame_busaddr + MFI_FRAME_SIZE; 942263363Semaste cm->cm_data = NULL; 943263363Semaste cm->cm_flags = MFI_CMD_POLLED; 944263363Semaste 945263363Semaste if ((error = mfi_mapcmd(sc, cm)) != 0) { 946263363Semaste device_printf(sc->mfi_dev, "failed to send init command\n"); 947263363Semaste mtx_unlock(&sc->mfi_io_lock); 948263363Semaste return (error); 949263363Semaste } 950263363Semaste mfi_release_command(cm); 951263363Semaste mtx_unlock(&sc->mfi_io_lock); 952263363Semaste 953263363Semaste return (0); 954263363Semaste} 955263363Semaste 956263363Semastestatic int 957263363Semastemfi_get_controller_info(struct mfi_softc *sc) 958263363Semaste{ 959263363Semaste struct mfi_command *cm = NULL; 960269024Semaste struct mfi_ctrl_info *ci = NULL; 961269024Semaste uint32_t max_sectors_1, max_sectors_2; 962263363Semaste int error; 963263363Semaste 964263363Semaste mtx_lock(&sc->mfi_io_lock); 965263363Semaste error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_GETINFO, 966263363Semaste (void **)&ci, sizeof(*ci)); 967263363Semaste if (error) 968263363Semaste goto out; 969263363Semaste cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 970263363Semaste 971263363Semaste if ((error = mfi_mapcmd(sc, cm)) != 0) { 972263363Semaste device_printf(sc->mfi_dev, "Failed to get controller info\n"); 973263363Semaste sc->mfi_max_io = (sc->mfi_max_sge - 1) * PAGE_SIZE / 974263363Semaste MFI_SECTOR_LEN; 975263363Semaste error = 0; 976263363Semaste goto out; 977263363Semaste } 978263363Semaste 979263363Semaste bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 980263363Semaste BUS_DMASYNC_POSTREAD); 981263363Semaste bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 982263363Semaste 983263363Semaste max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io; 984263363Semaste max_sectors_2 = ci->max_request_size; 985263363Semaste sc->mfi_max_io = min(max_sectors_1, max_sectors_2); 986263363Semaste sc->disableOnlineCtrlReset = 987263363Semaste ci->properties.OnOffProperties.disableOnlineCtrlReset; 988263363Semaste 989263363Semasteout: 990263363Semaste if (ci) 991263363Semaste free(ci, M_MFIBUF); 992263363Semaste if (cm) 993263363Semaste mfi_release_command(cm); 994263363Semaste mtx_unlock(&sc->mfi_io_lock); 995263363Semaste return (error); 996263363Semaste} 997263363Semaste 998263363Semastestatic int 999263363Semastemfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state) 1000263363Semaste{ 1001263363Semaste struct mfi_command *cm = NULL; 1002263363Semaste int error; 1003263363Semaste 1004263363Semaste mtx_lock(&sc->mfi_io_lock); 1005263363Semaste error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO, 1006263363Semaste (void **)log_state, sizeof(**log_state)); 1007263363Semaste if (error) 1008269024Semaste goto out; 1009269024Semaste cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1010263363Semaste 1011263363Semaste if ((error = mfi_mapcmd(sc, cm)) != 0) { 1012263363Semaste device_printf(sc->mfi_dev, "Failed to get log state\n"); 1013263363Semaste goto out; 1014263363Semaste } 1015263363Semaste 1016263363Semaste bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1017263363Semaste BUS_DMASYNC_POSTREAD); 1018263363Semaste bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1019263363Semaste 1020263363Semasteout: 1021263363Semaste if (cm) 1022263363Semaste mfi_release_command(cm); 1023263363Semaste mtx_unlock(&sc->mfi_io_lock); 1024263363Semaste 1025269024Semaste return (error); 1026269024Semaste} 1027263363Semaste 1028263363Semasteint 1029263363Semastemfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start) 1030263363Semaste{ 1031263363Semaste struct mfi_evt_log_state *log_state = NULL; 1032263363Semaste union mfi_evt class_locale; 1033263363Semaste int error = 0; 1034263363Semaste uint32_t seq; 1035263363Semaste 1036263363Semaste class_locale.members.reserved = 0; 1037263363Semaste class_locale.members.locale = mfi_event_locale; 1038263363Semaste class_locale.members.evt_class = mfi_event_class; 1039263363Semaste 1040263363Semaste if (seq_start == 0) { 1041263363Semaste error = mfi_get_log_state(sc, &log_state); 1042263363Semaste sc->mfi_boot_seq_num = log_state->boot_seq_num; 1043263363Semaste if (error) { 1044263363Semaste if (log_state) 1045263363Semaste free(log_state, M_MFIBUF); 1046263363Semaste return (error); 1047263363Semaste } 1048263363Semaste 1049263363Semaste /* 1050263363Semaste * Walk through any events that fired since the last 1051263363Semaste * shutdown. 1052263363Semaste */ 1053269024Semaste mfi_parse_entries(sc, log_state->shutdown_seq_num, 1054269024Semaste log_state->newest_seq_num); 1055263363Semaste seq = log_state->newest_seq_num; 1056263363Semaste } else 1057263363Semaste seq = seq_start; 1058263363Semaste mfi_aen_register(sc, seq, class_locale.word); 1059263363Semaste free(log_state, M_MFIBUF); 1060263363Semaste 1061263363Semaste return 0; 1062263363Semaste} 1063263363Semaste 1064263363Semasteint 1065263363Semastemfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm) 1066263363Semaste{ 1067263363Semaste 1068263363Semaste mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1069263363Semaste cm->cm_complete = NULL; 1070263363Semaste 1071263363Semaste 1072263363Semaste /* 1073263363Semaste * MegaCli can issue a DCMD of 0. In this case do nothing 1074263363Semaste * and return 0 to it as status 1075263363Semaste */ 1076263363Semaste if (cm->cm_frame->dcmd.opcode == 0) { 1077263363Semaste cm->cm_frame->header.cmd_status = MFI_STAT_OK; 1078263363Semaste cm->cm_error = 0; 1079263363Semaste return (cm->cm_error); 1080263363Semaste } 1081263363Semaste mfi_enqueue_ready(cm); 1082263363Semaste mfi_startio(sc); 1083263363Semaste if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0) 1084263363Semaste msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0); 1085263363Semaste return (cm->cm_error); 1086269024Semaste} 1087269024Semaste 1088263363Semastevoid 1089263363Semastemfi_free(struct mfi_softc *sc) 1090263363Semaste{ 1091263363Semaste struct mfi_command *cm; 1092263363Semaste int i; 1093263363Semaste 1094263363Semaste callout_drain(&sc->mfi_watchdog_callout); 1095263363Semaste 1096263363Semaste if (sc->mfi_cdev != NULL) 1097263363Semaste destroy_dev(sc->mfi_cdev); 1098263363Semaste 1099263363Semaste if (sc->mfi_total_cmds != 0) { 1100263363Semaste for (i = 0; i < sc->mfi_total_cmds; i++) { 1101263363Semaste cm = &sc->mfi_commands[i]; 1102263363Semaste bus_dmamap_destroy(sc->mfi_buffer_dmat, cm->cm_dmamap); 1103263363Semaste } 1104263363Semaste free(sc->mfi_commands, M_MFIBUF); 1105263363Semaste } 1106263363Semaste 1107263363Semaste if (sc->mfi_intr) 1108263363Semaste bus_teardown_intr(sc->mfi_dev, sc->mfi_irq, sc->mfi_intr); 1109263363Semaste if (sc->mfi_irq != NULL) 1110263363Semaste bus_release_resource(sc->mfi_dev, SYS_RES_IRQ, sc->mfi_irq_rid, 1111263363Semaste sc->mfi_irq); 1112269024Semaste 1113269024Semaste if (sc->mfi_sense_busaddr != 0) 1114263363Semaste bus_dmamap_unload(sc->mfi_sense_dmat, sc->mfi_sense_dmamap); 1115263363Semaste if (sc->mfi_sense != NULL) 1116263363Semaste bus_dmamem_free(sc->mfi_sense_dmat, sc->mfi_sense, 1117263363Semaste sc->mfi_sense_dmamap); 1118263363Semaste if (sc->mfi_sense_dmat != NULL) 1119263363Semaste bus_dma_tag_destroy(sc->mfi_sense_dmat); 1120263363Semaste 1121263363Semaste if (sc->mfi_frames_busaddr != 0) 1122263363Semaste bus_dmamap_unload(sc->mfi_frames_dmat, sc->mfi_frames_dmamap); 1123263363Semaste if (sc->mfi_frames != NULL) 1124263363Semaste bus_dmamem_free(sc->mfi_frames_dmat, sc->mfi_frames, 1125263363Semaste sc->mfi_frames_dmamap); 1126263363Semaste if (sc->mfi_frames_dmat != NULL) 1127263363Semaste bus_dma_tag_destroy(sc->mfi_frames_dmat); 1128263363Semaste 1129263363Semaste if (sc->mfi_comms_busaddr != 0) 1130263363Semaste bus_dmamap_unload(sc->mfi_comms_dmat, sc->mfi_comms_dmamap); 1131263363Semaste if (sc->mfi_comms != NULL) 1132263363Semaste bus_dmamem_free(sc->mfi_comms_dmat, sc->mfi_comms, 1133263363Semaste sc->mfi_comms_dmamap); 1134263363Semaste if (sc->mfi_comms_dmat != NULL) 1135263363Semaste bus_dma_tag_destroy(sc->mfi_comms_dmat); 1136263363Semaste 1137263363Semaste /* ThunderBolt contiguous memory free here */ 1138263363Semaste if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 1139263363Semaste if (sc->mfi_tb_busaddr != 0) 1140263363Semaste bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap); 1141263363Semaste if (sc->request_message_pool != NULL) 1142263363Semaste bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool, 1143263363Semaste sc->mfi_tb_dmamap); 1144263363Semaste if (sc->mfi_tb_dmat != NULL) 1145263363Semaste bus_dma_tag_destroy(sc->mfi_tb_dmat); 1146263363Semaste 1147263363Semaste /* Version buffer memory free */ 1148263363Semaste /* Start LSIP200113393 */ 1149263363Semaste if (sc->verbuf_h_busaddr != 0) 1150263363Semaste bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap); 1151263363Semaste if (sc->verbuf != NULL) 1152263363Semaste bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf, 1153263363Semaste sc->verbuf_h_dmamap); 1154263363Semaste if (sc->verbuf_h_dmat != NULL) 1155263363Semaste bus_dma_tag_destroy(sc->verbuf_h_dmat); 1156263363Semaste 1157263363Semaste /* End LSIP200113393 */ 1158263363Semaste /* ThunderBolt INIT packet memory Free */ 1159263363Semaste if (sc->mfi_tb_init_busaddr != 0) 1160263363Semaste bus_dmamap_unload(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap); 1161263363Semaste if (sc->mfi_tb_init != NULL) 1162263363Semaste bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init, 1163269024Semaste sc->mfi_tb_init_dmamap); 1164269024Semaste if (sc->mfi_tb_init_dmat != NULL) 1165269024Semaste bus_dma_tag_destroy(sc->mfi_tb_init_dmat); 1166263363Semaste 1167269024Semaste /* ThunderBolt IOC Init Desc memory free here */ 1168263363Semaste if (sc->mfi_tb_ioc_init_busaddr != 0) 1169263363Semaste bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat, 1170263363Semaste sc->mfi_tb_ioc_init_dmamap); 1171263363Semaste if (sc->mfi_tb_ioc_init_desc != NULL) 1172263363Semaste bus_dmamem_free(sc->mfi_tb_ioc_init_dmat, 1173263363Semaste sc->mfi_tb_ioc_init_desc, 1174263363Semaste sc->mfi_tb_ioc_init_dmamap); 1175263363Semaste if (sc->mfi_tb_ioc_init_dmat != NULL) 1176263363Semaste bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat); 1177263363Semaste for (int i = 0; i < sc->mfi_max_fw_cmds; i++) { 1178263363Semaste if (sc->mfi_cmd_pool_tbolt != NULL) { 1179263363Semaste if (sc->mfi_cmd_pool_tbolt[i] != NULL) { 1180263363Semaste free(sc->mfi_cmd_pool_tbolt[i], 1181263363Semaste M_MFIBUF); 1182269024Semaste sc->mfi_cmd_pool_tbolt[i] = NULL; 1183269024Semaste } 1184263363Semaste } 1185263363Semaste } 1186263363Semaste if (sc->mfi_cmd_pool_tbolt != NULL) { 1187263363Semaste free(sc->mfi_cmd_pool_tbolt, M_MFIBUF); 1188263363Semaste sc->mfi_cmd_pool_tbolt = NULL; 1189263363Semaste } 1190263363Semaste if (sc->request_desc_pool != NULL) { 1191263363Semaste free(sc->request_desc_pool, M_MFIBUF); 1192263363Semaste sc->request_desc_pool = NULL; 1193263363Semaste } 1194263363Semaste } 1195263363Semaste if (sc->mfi_buffer_dmat != NULL) 1196263363Semaste bus_dma_tag_destroy(sc->mfi_buffer_dmat); 1197269024Semaste if (sc->mfi_parent_dmat != NULL) 1198263363Semaste bus_dma_tag_destroy(sc->mfi_parent_dmat); 1199263363Semaste 1200263363Semaste if (mtx_initialized(&sc->mfi_io_lock)) { 1201263363Semaste mtx_destroy(&sc->mfi_io_lock); 1202263363Semaste sx_destroy(&sc->mfi_config_lock); 1203263363Semaste } 1204263363Semaste 1205263363Semaste return; 1206263363Semaste} 1207263363Semaste 1208269024Semastestatic void 1209269024Semastemfi_startup(void *arg) 1210263363Semaste{ 1211263363Semaste struct mfi_softc *sc; 1212269024Semaste 1213269024Semaste sc = (struct mfi_softc *)arg; 1214263363Semaste 1215263363Semaste config_intrhook_disestablish(&sc->mfi_ich); 1216263363Semaste 1217263363Semaste sc->mfi_enable_intr(sc); 1218263363Semaste sx_xlock(&sc->mfi_config_lock); 1219263363Semaste mtx_lock(&sc->mfi_io_lock); 1220263363Semaste mfi_ldprobe(sc); 1221263363Semaste if (sc->mfi_flags & MFI_FLAGS_SKINNY) 1222263363Semaste mfi_syspdprobe(sc); 1223263363Semaste mtx_unlock(&sc->mfi_io_lock); 1224263363Semaste sx_xunlock(&sc->mfi_config_lock); 1225263363Semaste} 1226263363Semaste 1227263363Semastestatic void 1228263363Semastemfi_intr(void *arg) 1229269024Semaste{ 1230269024Semaste struct mfi_softc *sc; 1231263363Semaste struct mfi_command *cm; 1232263363Semaste uint32_t pi, ci, context; 1233263363Semaste 1234263363Semaste sc = (struct mfi_softc *)arg; 1235263363Semaste 1236263363Semaste if (sc->mfi_check_clear_intr(sc)) 1237263363Semaste return; 1238263363Semaste 1239269024Semasterestart: 1240269024Semaste pi = sc->mfi_comms->hw_pi; 1241263363Semaste ci = sc->mfi_comms->hw_ci; 1242263363Semaste mtx_lock(&sc->mfi_io_lock); 1243269024Semaste while (ci != pi) { 1244269024Semaste context = sc->mfi_comms->hw_reply_q[ci]; 1245263363Semaste if (context < sc->mfi_max_fw_cmds) { 1246263363Semaste cm = &sc->mfi_commands[context]; 1247263363Semaste mfi_remove_busy(cm); 1248263363Semaste cm->cm_error = 0; 1249263363Semaste mfi_complete(sc, cm); 1250263363Semaste } 1251263363Semaste if (++ci == (sc->mfi_max_fw_cmds + 1)) { 1252263363Semaste ci = 0; 1253263363Semaste } 1254263363Semaste } 1255263363Semaste 1256263363Semaste sc->mfi_comms->hw_ci = ci; 1257269024Semaste 1258269024Semaste /* Give defered I/O a chance to run */ 1259269024Semaste if (sc->mfi_flags & MFI_FLAGS_QFRZN) 1260263363Semaste sc->mfi_flags &= ~MFI_FLAGS_QFRZN; 1261269024Semaste mfi_startio(sc); 1262263363Semaste mtx_unlock(&sc->mfi_io_lock); 1263263363Semaste 1264263363Semaste /* 1265269024Semaste * Dummy read to flush the bus; this ensures that the indexes are up 1266263363Semaste * to date. Restart processing if more commands have come it. 1267263363Semaste */ 1268263363Semaste (void)sc->mfi_read_fw_status(sc); 1269263363Semaste if (pi != sc->mfi_comms->hw_pi) 1270263363Semaste goto restart; 1271263363Semaste 1272263363Semaste return; 1273263363Semaste} 1274263363Semaste 1275263363Semasteint 1276269024Semastemfi_shutdown(struct mfi_softc *sc) 1277269024Semaste{ 1278263363Semaste struct mfi_dcmd_frame *dcmd; 1279263363Semaste struct mfi_command *cm; 1280269024Semaste int error; 1281269024Semaste 1282263363Semaste mtx_lock(&sc->mfi_io_lock); 1283263363Semaste error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_SHUTDOWN, NULL, 0); 1284263363Semaste if (error) { 1285263363Semaste mtx_unlock(&sc->mfi_io_lock); 1286263363Semaste return (error); 1287263363Semaste } 1288263363Semaste 1289263363Semaste if (sc->mfi_aen_cm != NULL) 1290263363Semaste mfi_abort(sc, sc->mfi_aen_cm); 1291263363Semaste 1292263363Semaste if (sc->mfi_map_sync_cm != NULL) 1293263363Semaste mfi_abort(sc, sc->mfi_map_sync_cm); 1294263363Semaste 1295263363Semaste dcmd = &cm->cm_frame->dcmd; 1296263363Semaste dcmd->header.flags = MFI_FRAME_DIR_NONE; 1297263363Semaste cm->cm_flags = MFI_CMD_POLLED; 1298263363Semaste cm->cm_data = NULL; 1299263363Semaste 1300263363Semaste if ((error = mfi_mapcmd(sc, cm)) != 0) { 1301263363Semaste device_printf(sc->mfi_dev, "Failed to shutdown controller\n"); 1302263363Semaste } 1303263363Semaste 1304263363Semaste mfi_release_command(cm); 1305263363Semaste mtx_unlock(&sc->mfi_io_lock); 1306263363Semaste return (error); 1307269024Semaste} 1308269024Semaste 1309263363Semastestatic void 1310263363Semastemfi_syspdprobe(struct mfi_softc *sc) 1311263363Semaste{ 1312263363Semaste struct mfi_frame_header *hdr; 1313263363Semaste struct mfi_command *cm = NULL; 1314263363Semaste struct mfi_pd_list *pdlist = NULL; 1315263363Semaste struct mfi_system_pd *syspd, *tmp; 1316263363Semaste int error, i, found; 1317263363Semaste 1318263363Semaste sx_assert(&sc->mfi_config_lock, SA_XLOCKED); 1319263363Semaste mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1320263363Semaste /* Add SYSTEM PD's */ 1321263363Semaste error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY, 1322263363Semaste (void **)&pdlist, sizeof(*pdlist)); 1323263363Semaste if (error) { 1324263363Semaste device_printf(sc->mfi_dev, 1325263363Semaste "Error while forming SYSTEM PD list\n"); 1326263363Semaste goto out; 1327263363Semaste } 1328263363Semaste 1329263363Semaste cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1330263363Semaste cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST; 1331263363Semaste cm->cm_frame->dcmd.mbox[1] = 0; 1332269024Semaste if (mfi_mapcmd(sc, cm) != 0) { 1333269024Semaste device_printf(sc->mfi_dev, 1334263363Semaste "Failed to get syspd device listing\n"); 1335263363Semaste goto out; 1336263363Semaste } 1337263363Semaste bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap, 1338263363Semaste BUS_DMASYNC_POSTREAD); 1339263363Semaste bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1340263363Semaste hdr = &cm->cm_frame->header; 1341263363Semaste if (hdr->cmd_status != MFI_STAT_OK) { 1342263363Semaste device_printf(sc->mfi_dev, 1343269024Semaste "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status); 1344269024Semaste goto out; 1345263363Semaste } 1346263363Semaste /* Get each PD and add it to the system */ 1347263363Semaste for (i = 0; i < pdlist->count; i++) { 1348263363Semaste if (pdlist->addr[i].device_id == 1349269024Semaste pdlist->addr[i].encl_device_id) 1350269024Semaste continue; 1351263363Semaste found = 0; 1352263363Semaste TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { 1353263363Semaste if (syspd->pd_id == pdlist->addr[i].device_id) 1354263363Semaste found = 1; 1355263363Semaste } 1356263363Semaste if (found == 0) 1357263363Semaste mfi_add_sys_pd(sc, pdlist->addr[i].device_id); 1358263363Semaste } 1359263363Semaste /* Delete SYSPD's whose state has been changed */ 1360263363Semaste TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) { 1361269024Semaste found = 0; 1362269024Semaste for (i = 0; i < pdlist->count; i++) { 1363263363Semaste if (syspd->pd_id == pdlist->addr[i].device_id) 1364263363Semaste found = 1; 1365263363Semaste } 1366263363Semaste if (found == 0) { 1367263363Semaste printf("DELETE\n"); 1368263363Semaste mtx_unlock(&sc->mfi_io_lock); 1369263363Semaste mtx_lock(&Giant); 1370263363Semaste device_delete_child(sc->mfi_dev, syspd->pd_dev); 1371263363Semaste mtx_unlock(&Giant); 1372263363Semaste mtx_lock(&sc->mfi_io_lock); 1373263363Semaste } 1374263363Semaste } 1375263363Semasteout: 1376263363Semaste if (pdlist) 1377263363Semaste free(pdlist, M_MFIBUF); 1378263363Semaste if (cm) 1379263363Semaste mfi_release_command(cm); 1380263363Semaste 1381263363Semaste return; 1382263363Semaste} 1383263363Semaste 1384263363Semastestatic void 1385263363Semastemfi_ldprobe(struct mfi_softc *sc) 1386263363Semaste{ 1387263363Semaste struct mfi_frame_header *hdr; 1388263363Semaste struct mfi_command *cm = NULL; 1389263363Semaste struct mfi_ld_list *list = NULL; 1390263363Semaste struct mfi_disk *ld; 1391263363Semaste int error, i; 1392263363Semaste 1393263363Semaste sx_assert(&sc->mfi_config_lock, SA_XLOCKED); 1394263363Semaste mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1395263363Semaste 1396263363Semaste error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST, 1397263363Semaste (void **)&list, sizeof(*list)); 1398263363Semaste if (error) 1399263363Semaste goto out; 1400263363Semaste 1401263363Semaste cm->cm_flags = MFI_CMD_DATAIN; 1402263363Semaste if (mfi_wait_command(sc, cm) != 0) { 1403263363Semaste device_printf(sc->mfi_dev, "Failed to get device listing\n"); 1404263363Semaste goto out; 1405269024Semaste } 1406269024Semaste 1407263363Semaste hdr = &cm->cm_frame->header; 1408263363Semaste if (hdr->cmd_status != MFI_STAT_OK) { 1409263363Semaste device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n", 1410263363Semaste hdr->cmd_status); 1411269024Semaste goto out; 1412269024Semaste } 1413263363Semaste 1414263363Semaste for (i = 0; i < list->ld_count; i++) { 1415263363Semaste TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 1416263363Semaste if (ld->ld_id == list->ld_list[i].ld.v.target_id) 1417263363Semaste goto skip_add; 1418263363Semaste } 1419263363Semaste mfi_add_ld(sc, list->ld_list[i].ld.v.target_id); 1420263363Semaste skip_add:; 1421263363Semaste } 1422263363Semasteout: 1423263363Semaste if (list) 1424263363Semaste free(list, M_MFIBUF); 1425263363Semaste if (cm) 1426263363Semaste mfi_release_command(cm); 1427263363Semaste 1428263363Semaste return; 1429263363Semaste} 1430263363Semaste 1431263363Semaste/* 1432263363Semaste * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If 1433263363Semaste * the bits in 24-31 are all set, then it is the number of seconds since 1434263363Semaste * boot. 1435263363Semaste */ 1436263363Semastestatic const char * 1437263363Semasteformat_timestamp(uint32_t timestamp) 1438269024Semaste{ 1439269024Semaste static char buffer[32]; 1440263363Semaste 1441263363Semaste if ((timestamp & 0xff000000) == 0xff000000) 1442263363Semaste snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & 1443263363Semaste 0x00ffffff); 1444269024Semaste else 1445269024Semaste snprintf(buffer, sizeof(buffer), "%us", timestamp); 1446263363Semaste return (buffer); 1447263363Semaste} 1448263363Semaste 1449263363Semastestatic const char * 1450263363Semasteformat_class(int8_t class) 1451263363Semaste{ 1452263363Semaste static char buffer[6]; 1453263363Semaste 1454263363Semaste switch (class) { 1455263363Semaste case MFI_EVT_CLASS_DEBUG: 1456263363Semaste return ("debug"); 1457263363Semaste case MFI_EVT_CLASS_PROGRESS: 1458263363Semaste return ("progress"); 1459269024Semaste case MFI_EVT_CLASS_INFO: 1460269024Semaste return ("info"); 1461263363Semaste case MFI_EVT_CLASS_WARNING: 1462263363Semaste return ("WARN"); 1463263363Semaste case MFI_EVT_CLASS_CRITICAL: 1464269024Semaste return ("CRIT"); 1465269024Semaste case MFI_EVT_CLASS_FATAL: 1466263363Semaste return ("FATAL"); 1467263363Semaste case MFI_EVT_CLASS_DEAD: 1468263363Semaste return ("DEAD"); 1469263363Semaste default: 1470263363Semaste snprintf(buffer, sizeof(buffer), "%d", class); 1471269024Semaste return (buffer); 1472269024Semaste } 1473263363Semaste} 1474263363Semaste 1475263363Semastestatic void 1476263363Semastemfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) 1477263363Semaste{ 1478263363Semaste struct mfi_system_pd *syspd = NULL; 1479263363Semaste 1480263363Semaste device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq, 1481263363Semaste format_timestamp(detail->time), detail->evt_class.members.locale, 1482263363Semaste format_class(detail->evt_class.members.evt_class), 1483263363Semaste detail->description); 1484263363Semaste 1485263363Semaste /* Don't act on old AEN's or while shutting down */ 1486263363Semaste if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching) 1487263363Semaste return; 1488263363Semaste 1489263363Semaste switch (detail->arg_type) { 1490263363Semaste case MR_EVT_ARGS_NONE: 1491263363Semaste if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) { 1492263363Semaste device_printf(sc->mfi_dev, "HostBus scan raised\n"); 1493263363Semaste if (mfi_detect_jbod_change) { 1494263363Semaste /* 1495263363Semaste * Probe for new SYSPD's and Delete 1496263363Semaste * invalid SYSPD's 1497263363Semaste */ 1498263363Semaste sx_xlock(&sc->mfi_config_lock); 1499263363Semaste mtx_lock(&sc->mfi_io_lock); 1500263363Semaste mfi_syspdprobe(sc); 1501263363Semaste mtx_unlock(&sc->mfi_io_lock); 1502263363Semaste sx_xunlock(&sc->mfi_config_lock); 1503263363Semaste } 1504263363Semaste } 1505263363Semaste break; 1506263363Semaste case MR_EVT_ARGS_LD_STATE: 1507263363Semaste /* During load time driver reads all the events starting 1508263363Semaste * from the one that has been logged after shutdown. Avoid 1509263363Semaste * these old events. 1510263363Semaste */ 1511263363Semaste if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) { 1512263363Semaste /* Remove the LD */ 1513263363Semaste struct mfi_disk *ld; 1514263363Semaste TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 1515263363Semaste if (ld->ld_id == 1516263363Semaste detail->args.ld_state.ld.target_id) 1517263363Semaste break; 1518263363Semaste } 1519263363Semaste /* 1520263363Semaste Fix: for kernel panics when SSCD is removed 1521263363Semaste KASSERT(ld != NULL, ("volume dissappeared")); 1522263363Semaste */ 1523263363Semaste if (ld != NULL) { 1524263363Semaste mtx_lock(&Giant); 1525263363Semaste device_delete_child(sc->mfi_dev, ld->ld_dev); 1526263363Semaste mtx_unlock(&Giant); 1527263363Semaste } 1528263363Semaste } 1529263363Semaste break; 1530263363Semaste case MR_EVT_ARGS_PD: 1531263363Semaste if (detail->code == MR_EVT_PD_REMOVED) { 1532263363Semaste if (mfi_detect_jbod_change) { 1533263363Semaste /* 1534269024Semaste * If the removed device is a SYSPD then 1535269024Semaste * delete it 1536263363Semaste */ 1537263363Semaste TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, 1538263363Semaste pd_link) { 1539263363Semaste if (syspd->pd_id == 1540269024Semaste detail->args.pd.device_id) { 1541269024Semaste mtx_lock(&Giant); 1542263363Semaste device_delete_child( 1543263363Semaste sc->mfi_dev, 1544263363Semaste syspd->pd_dev); 1545263363Semaste mtx_unlock(&Giant); 1546263363Semaste break; 1547263363Semaste } 1548263363Semaste } 1549263363Semaste } 1550263363Semaste } 1551263363Semaste if (detail->code == MR_EVT_PD_INSERTED) { 1552269024Semaste if (mfi_detect_jbod_change) { 1553269024Semaste /* Probe for new SYSPD's */ 1554263363Semaste sx_xlock(&sc->mfi_config_lock); 1555263363Semaste mtx_lock(&sc->mfi_io_lock); 1556263363Semaste mfi_syspdprobe(sc); 1557263363Semaste mtx_unlock(&sc->mfi_io_lock); 1558263363Semaste sx_xunlock(&sc->mfi_config_lock); 1559263363Semaste } 1560263363Semaste } 1561263363Semaste break; 1562263363Semaste } 1563263363Semaste} 1564263363Semaste 1565263363Semastestatic void 1566263363Semastemfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail) 1567263363Semaste{ 1568263363Semaste struct mfi_evt_queue_elm *elm; 1569263363Semaste 1570263363Semaste mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1571263363Semaste elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO); 1572263363Semaste if (elm == NULL) 1573263363Semaste return; 1574263363Semaste memcpy(&elm->detail, detail, sizeof(*detail)); 1575263363Semaste TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link); 1576263363Semaste taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task); 1577269024Semaste} 1578269024Semaste 1579263363Semastestatic void 1580263363Semastemfi_handle_evt(void *context, int pending) 1581263363Semaste{ 1582263363Semaste TAILQ_HEAD(,mfi_evt_queue_elm) queue; 1583263363Semaste struct mfi_softc *sc; 1584263363Semaste struct mfi_evt_queue_elm *elm; 1585263363Semaste 1586263363Semaste sc = context; 1587263363Semaste TAILQ_INIT(&queue); 1588263363Semaste mtx_lock(&sc->mfi_io_lock); 1589263363Semaste TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link); 1590263363Semaste mtx_unlock(&sc->mfi_io_lock); 1591263363Semaste while ((elm = TAILQ_FIRST(&queue)) != NULL) { 1592263363Semaste TAILQ_REMOVE(&queue, elm, link); 1593263363Semaste mfi_decode_evt(sc, &elm->detail); 1594263363Semaste free(elm, M_MFIBUF); 1595263363Semaste } 1596263363Semaste} 1597263363Semaste 1598263363Semastestatic int 1599263363Semastemfi_aen_register(struct mfi_softc *sc, int seq, int locale) 1600263363Semaste{ 1601263363Semaste struct mfi_command *cm; 1602263363Semaste struct mfi_dcmd_frame *dcmd; 1603263363Semaste union mfi_evt current_aen, prior_aen; 1604263363Semaste struct mfi_evt_detail *ed = NULL; 1605263363Semaste int error = 0; 1606263363Semaste 1607263363Semaste current_aen.word = locale; 1608263363Semaste if (sc->mfi_aen_cm != NULL) { 1609263363Semaste prior_aen.word = 1610263363Semaste ((uint32_t *)&sc->mfi_aen_cm->cm_frame->dcmd.mbox)[1]; 1611263363Semaste if (prior_aen.members.evt_class <= current_aen.members.evt_class && 1612263363Semaste !((prior_aen.members.locale & current_aen.members.locale) 1613263363Semaste ^current_aen.members.locale)) { 1614263363Semaste return (0); 1615263363Semaste } else { 1616263363Semaste prior_aen.members.locale |= current_aen.members.locale; 1617263363Semaste if (prior_aen.members.evt_class 1618263363Semaste < current_aen.members.evt_class) 1619263363Semaste current_aen.members.evt_class = 1620263363Semaste prior_aen.members.evt_class; 1621263363Semaste mtx_lock(&sc->mfi_io_lock); 1622263363Semaste mfi_abort(sc, sc->mfi_aen_cm); 1623263363Semaste mtx_unlock(&sc->mfi_io_lock); 1624263363Semaste } 1625263363Semaste } 1626263363Semaste 1627263363Semaste mtx_lock(&sc->mfi_io_lock); 1628263363Semaste error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT, 1629263363Semaste (void **)&ed, sizeof(*ed)); 1630263363Semaste mtx_unlock(&sc->mfi_io_lock); 1631263363Semaste if (error) { 1632263363Semaste goto out; 1633263363Semaste } 1634263363Semaste 1635263363Semaste dcmd = &cm->cm_frame->dcmd; 1636263363Semaste ((uint32_t *)&dcmd->mbox)[0] = seq; 1637263363Semaste ((uint32_t *)&dcmd->mbox)[1] = locale; 1638263363Semaste cm->cm_flags = MFI_CMD_DATAIN; 1639263363Semaste cm->cm_complete = mfi_aen_complete; 1640263363Semaste 1641263363Semaste sc->last_seq_num = seq; 1642263363Semaste sc->mfi_aen_cm = cm; 1643263363Semaste 1644263363Semaste mtx_lock(&sc->mfi_io_lock); 1645263363Semaste mfi_enqueue_ready(cm); 1646263363Semaste mfi_startio(sc); 1647263363Semaste mtx_unlock(&sc->mfi_io_lock); 1648263363Semaste 1649263363Semasteout: 1650263363Semaste return (error); 1651263363Semaste} 1652263363Semaste 1653263363Semastestatic void 1654263363Semastemfi_aen_complete(struct mfi_command *cm) 1655263363Semaste{ 1656263363Semaste struct mfi_frame_header *hdr; 1657263363Semaste struct mfi_softc *sc; 1658263363Semaste struct mfi_evt_detail *detail; 1659263363Semaste struct mfi_aen *mfi_aen_entry, *tmp; 1660263363Semaste int seq = 0, aborted = 0; 1661263363Semaste 1662263363Semaste sc = cm->cm_sc; 1663263363Semaste mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1664263363Semaste 1665263363Semaste hdr = &cm->cm_frame->header; 1666263363Semaste 1667263363Semaste if (sc->mfi_aen_cm == NULL) 1668263363Semaste return; 1669263363Semaste 1670263363Semaste if (sc->cm_aen_abort || 1671269024Semaste hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 1672269024Semaste sc->cm_aen_abort = 0; 1673263363Semaste aborted = 1; 1674263363Semaste } else { 1675263363Semaste sc->mfi_aen_triggered = 1; 1676263363Semaste if (sc->mfi_poll_waiting) { 1677263363Semaste sc->mfi_poll_waiting = 0; 1678263363Semaste selwakeup(&sc->mfi_select); 1679263363Semaste } 1680263363Semaste detail = cm->cm_data; 1681263363Semaste mfi_queue_evt(sc, detail); 1682263363Semaste seq = detail->seq + 1; 1683263363Semaste TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, 1684263363Semaste tmp) { 1685263363Semaste TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 1686263363Semaste aen_link); 1687263363Semaste PROC_LOCK(mfi_aen_entry->p); 1688263363Semaste kern_psignal(mfi_aen_entry->p, SIGIO); 1689263363Semaste PROC_UNLOCK(mfi_aen_entry->p); 1690263363Semaste free(mfi_aen_entry, M_MFIBUF); 1691263363Semaste } 1692263363Semaste } 1693263363Semaste 1694263363Semaste free(cm->cm_data, M_MFIBUF); 1695263363Semaste sc->mfi_aen_cm = NULL; 1696269024Semaste wakeup(&sc->mfi_aen_cm); 1697269024Semaste mfi_release_command(cm); 1698263363Semaste 1699263363Semaste /* set it up again so the driver can catch more events */ 1700263363Semaste if (!aborted) { 1701263363Semaste mtx_unlock(&sc->mfi_io_lock); 1702263363Semaste mfi_aen_setup(sc, seq); 1703263363Semaste mtx_lock(&sc->mfi_io_lock); 1704263363Semaste } 1705263363Semaste} 1706263363Semaste 1707263363Semaste#define MAX_EVENTS 15 1708263363Semaste 1709263363Semastestatic int 1710263363Semastemfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq) 1711263363Semaste{ 1712263363Semaste struct mfi_command *cm; 1713263363Semaste struct mfi_dcmd_frame *dcmd; 1714263363Semaste struct mfi_evt_list *el; 1715263363Semaste union mfi_evt class_locale; 1716263363Semaste int error, i, seq, size; 1717263363Semaste 1718263363Semaste class_locale.members.reserved = 0; 1719263363Semaste class_locale.members.locale = mfi_event_locale; 1720263363Semaste class_locale.members.evt_class = mfi_event_class; 1721263363Semaste 1722263363Semaste size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) 1723263363Semaste * (MAX_EVENTS - 1); 1724263363Semaste el = malloc(size, M_MFIBUF, M_NOWAIT | M_ZERO); 1725263363Semaste if (el == NULL) 1726263363Semaste return (ENOMEM); 1727263363Semaste 1728263363Semaste for (seq = start_seq;;) { 1729263363Semaste mtx_lock(&sc->mfi_io_lock); 1730263363Semaste if ((cm = mfi_dequeue_free(sc)) == NULL) { 1731263363Semaste free(el, M_MFIBUF); 1732269024Semaste mtx_unlock(&sc->mfi_io_lock); 1733269024Semaste return (EBUSY); 1734263363Semaste } 1735263363Semaste mtx_unlock(&sc->mfi_io_lock); 1736263363Semaste 1737263363Semaste dcmd = &cm->cm_frame->dcmd; 1738263363Semaste bzero(dcmd->mbox, MFI_MBOX_SIZE); 1739263363Semaste dcmd->header.cmd = MFI_CMD_DCMD; 1740263363Semaste dcmd->header.timeout = 0; 1741263363Semaste dcmd->header.data_len = size; 1742263363Semaste dcmd->opcode = MFI_DCMD_CTRL_EVENT_GET; 1743263363Semaste ((uint32_t *)&dcmd->mbox)[0] = seq; 1744263363Semaste ((uint32_t *)&dcmd->mbox)[1] = class_locale.word; 1745263363Semaste cm->cm_sg = &dcmd->sgl; 1746263363Semaste cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 1747263363Semaste cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1748269024Semaste cm->cm_data = el; 1749269024Semaste cm->cm_len = size; 1750263363Semaste 1751263363Semaste mtx_lock(&sc->mfi_io_lock); 1752263363Semaste if ((error = mfi_mapcmd(sc, cm)) != 0) { 1753263363Semaste device_printf(sc->mfi_dev, 1754263363Semaste "Failed to get controller entries\n"); 1755263363Semaste mfi_release_command(cm); 1756263363Semaste mtx_unlock(&sc->mfi_io_lock); 1757263363Semaste break; 1758263363Semaste } 1759263363Semaste 1760263363Semaste mtx_unlock(&sc->mfi_io_lock); 1761263363Semaste bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1762263363Semaste BUS_DMASYNC_POSTREAD); 1763263363Semaste bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1764263363Semaste 1765269024Semaste if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) { 1766269024Semaste mtx_lock(&sc->mfi_io_lock); 1767263363Semaste mfi_release_command(cm); 1768263363Semaste mtx_unlock(&sc->mfi_io_lock); 1769263363Semaste break; 1770263363Semaste } 1771263363Semaste if (dcmd->header.cmd_status != MFI_STAT_OK) { 1772263363Semaste device_printf(sc->mfi_dev, 1773263363Semaste "Error %d fetching controller entries\n", 1774263363Semaste dcmd->header.cmd_status); 1775263363Semaste mtx_lock(&sc->mfi_io_lock); 1776263363Semaste mfi_release_command(cm); 1777263363Semaste mtx_unlock(&sc->mfi_io_lock); 1778263363Semaste break; 1779263363Semaste } 1780263363Semaste mtx_lock(&sc->mfi_io_lock); 1781263363Semaste mfi_release_command(cm); 1782263363Semaste mtx_unlock(&sc->mfi_io_lock); 1783263363Semaste 1784263363Semaste for (i = 0; i < el->count; i++) { 1785263363Semaste /* 1786263363Semaste * If this event is newer than 'stop_seq' then 1787263363Semaste * break out of the loop. Note that the log 1788263363Semaste * is a circular buffer so we have to handle 1789263363Semaste * the case that our stop point is earlier in 1790263363Semaste * the buffer than our start point. 1791263363Semaste */ 1792263363Semaste if (el->event[i].seq >= stop_seq) { 1793263363Semaste if (start_seq <= stop_seq) 1794263363Semaste break; 1795263363Semaste else if (el->event[i].seq < start_seq) 1796263363Semaste break; 1797263363Semaste } 1798263363Semaste mtx_lock(&sc->mfi_io_lock); 1799269024Semaste mfi_queue_evt(sc, &el->event[i]); 1800269024Semaste mtx_unlock(&sc->mfi_io_lock); 1801263363Semaste } 1802263363Semaste seq = el->event[el->count - 1].seq + 1; 1803263363Semaste } 1804263363Semaste 1805263363Semaste free(el, M_MFIBUF); 1806263363Semaste return (0); 1807263363Semaste} 1808263363Semaste 1809263363Semastestatic int 1810263363Semastemfi_add_ld(struct mfi_softc *sc, int id) 1811263363Semaste{ 1812263363Semaste struct mfi_command *cm; 1813263363Semaste struct mfi_dcmd_frame *dcmd = NULL; 1814263363Semaste struct mfi_ld_info *ld_info = NULL; 1815263363Semaste int error; 1816263363Semaste 1817263363Semaste mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1818263363Semaste 1819263363Semaste error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_INFO, 1820263363Semaste (void **)&ld_info, sizeof(*ld_info)); 1821263363Semaste if (error) { 1822263363Semaste device_printf(sc->mfi_dev, 1823263363Semaste "Failed to allocate for MFI_DCMD_LD_GET_INFO %d\n", error); 1824263363Semaste if (ld_info) 1825263363Semaste free(ld_info, M_MFIBUF); 1826263363Semaste return (error); 1827263363Semaste } 1828263363Semaste cm->cm_flags = MFI_CMD_DATAIN; 1829263363Semaste dcmd = &cm->cm_frame->dcmd; 1830263363Semaste dcmd->mbox[0] = id; 1831263363Semaste if (mfi_wait_command(sc, cm) != 0) { 1832263363Semaste device_printf(sc->mfi_dev, 1833263363Semaste "Failed to get logical drive: %d\n", id); 1834263363Semaste free(ld_info, M_MFIBUF); 1835263363Semaste return (0); 1836263363Semaste } 1837263363Semaste if (ld_info->ld_config.params.isSSCD != 1) 1838269024Semaste mfi_add_ld_complete(cm); 1839269024Semaste else { 1840263363Semaste mfi_release_command(cm); 1841263363Semaste if (ld_info) /* SSCD drives ld_info free here */ 1842263363Semaste free(ld_info, M_MFIBUF); 1843263363Semaste } 1844263363Semaste return (0); 1845263363Semaste} 1846263363Semaste 1847263363Semastestatic void 1848263363Semastemfi_add_ld_complete(struct mfi_command *cm) 1849263363Semaste{ 1850263363Semaste struct mfi_frame_header *hdr; 1851263363Semaste struct mfi_ld_info *ld_info; 1852263363Semaste struct mfi_softc *sc; 1853263363Semaste device_t child; 1854263363Semaste 1855263363Semaste sc = cm->cm_sc; 1856263363Semaste hdr = &cm->cm_frame->header; 1857263363Semaste ld_info = cm->cm_private; 1858263363Semaste 1859263363Semaste if (hdr->cmd_status != MFI_STAT_OK) { 1860263363Semaste free(ld_info, M_MFIBUF); 1861269024Semaste mfi_release_command(cm); 1862269024Semaste return; 1863263363Semaste } 1864263363Semaste mfi_release_command(cm); 1865263363Semaste 1866263363Semaste mtx_unlock(&sc->mfi_io_lock); 1867263363Semaste mtx_lock(&Giant); 1868263363Semaste if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) { 1869263363Semaste device_printf(sc->mfi_dev, "Failed to add logical disk\n"); 1870263363Semaste free(ld_info, M_MFIBUF); 1871263363Semaste mtx_unlock(&Giant); 1872263363Semaste mtx_lock(&sc->mfi_io_lock); 1873269024Semaste return; 1874269024Semaste } 1875263363Semaste 1876263363Semaste device_set_ivars(child, ld_info); 1877263363Semaste device_set_desc(child, "MFI Logical Disk"); 1878263363Semaste bus_generic_attach(sc->mfi_dev); 1879263363Semaste mtx_unlock(&Giant); 1880263363Semaste mtx_lock(&sc->mfi_io_lock); 1881263363Semaste} 1882263363Semaste 1883263363Semastestatic int mfi_add_sys_pd(struct mfi_softc *sc, int id) 1884263363Semaste{ 1885263363Semaste struct mfi_command *cm; 1886263363Semaste struct mfi_dcmd_frame *dcmd = NULL; 1887263363Semaste struct mfi_pd_info *pd_info = NULL; 1888263363Semaste int error; 1889263363Semaste 1890263363Semaste mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1891263363Semaste 1892263363Semaste error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO, 1893263363Semaste (void **)&pd_info, sizeof(*pd_info)); 1894263363Semaste if (error) { 1895263363Semaste device_printf(sc->mfi_dev, 1896263363Semaste "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n", 1897263363Semaste error); 1898263363Semaste if (pd_info) 1899263363Semaste free(pd_info, M_MFIBUF); 1900263363Semaste return (error); 1901263363Semaste } 1902263363Semaste cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED; 1903263363Semaste dcmd = &cm->cm_frame->dcmd; 1904263363Semaste dcmd->mbox[0]=id; 1905263363Semaste dcmd->header.scsi_status = 0; 1906263363Semaste dcmd->header.pad0 = 0; 1907263363Semaste if (mfi_mapcmd(sc, cm) != 0) { 1908263363Semaste device_printf(sc->mfi_dev, 1909263363Semaste "Failed to get physical drive info %d\n", id); 1910263363Semaste free(pd_info, M_MFIBUF); 1911263363Semaste return (0); 1912263363Semaste } 1913263363Semaste bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 1914263363Semaste BUS_DMASYNC_POSTREAD); 1915263363Semaste bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 1916263363Semaste mfi_add_sys_pd_complete(cm); 1917263363Semaste return (0); 1918263363Semaste} 1919263363Semaste 1920263363Semastestatic void 1921263363Semastemfi_add_sys_pd_complete(struct mfi_command *cm) 1922263363Semaste{ 1923263363Semaste struct mfi_frame_header *hdr; 1924263363Semaste struct mfi_pd_info *pd_info; 1925263363Semaste struct mfi_softc *sc; 1926263363Semaste device_t child; 1927263363Semaste 1928263363Semaste sc = cm->cm_sc; 1929263363Semaste hdr = &cm->cm_frame->header; 1930263363Semaste pd_info = cm->cm_private; 1931263363Semaste 1932263363Semaste if (hdr->cmd_status != MFI_STAT_OK) { 1933263363Semaste free(pd_info, M_MFIBUF); 1934263363Semaste mfi_release_command(cm); 1935263363Semaste return; 1936263363Semaste } 1937263363Semaste if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) { 1938263363Semaste device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n", 1939263363Semaste pd_info->ref.v.device_id); 1940263363Semaste free(pd_info, M_MFIBUF); 1941263363Semaste mfi_release_command(cm); 1942263363Semaste return; 1943263363Semaste } 1944263363Semaste mfi_release_command(cm); 1945263363Semaste 1946263363Semaste mtx_unlock(&sc->mfi_io_lock); 1947263363Semaste mtx_lock(&Giant); 1948263363Semaste if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) { 1949263363Semaste device_printf(sc->mfi_dev, "Failed to add system pd\n"); 1950263363Semaste free(pd_info, M_MFIBUF); 1951263363Semaste mtx_unlock(&Giant); 1952263363Semaste mtx_lock(&sc->mfi_io_lock); 1953263363Semaste return; 1954263363Semaste } 1955263363Semaste 1956263363Semaste device_set_ivars(child, pd_info); 1957263363Semaste device_set_desc(child, "MFI System PD"); 1958263363Semaste bus_generic_attach(sc->mfi_dev); 1959263363Semaste mtx_unlock(&Giant); 1960263363Semaste mtx_lock(&sc->mfi_io_lock); 1961263363Semaste} 1962263363Semaste 1963263363Semastestatic struct mfi_command * 1964263363Semastemfi_bio_command(struct mfi_softc *sc) 1965263363Semaste{ 1966263363Semaste struct bio *bio; 1967263363Semaste struct mfi_command *cm = NULL; 1968263363Semaste 1969263363Semaste /*reserving two commands to avoid starvation for IOCTL*/ 1970263363Semaste if (sc->mfi_qstat[MFIQ_FREE].q_length < 2) { 1971263363Semaste return (NULL); 1972263363Semaste } 1973263363Semaste if ((bio = mfi_dequeue_bio(sc)) == NULL) { 1974263363Semaste return (NULL); 1975263363Semaste } 1976263363Semaste if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) { 1977263363Semaste cm = mfi_build_ldio(sc, bio); 1978263363Semaste } else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) { 1979263363Semaste cm = mfi_build_syspdio(sc, bio); 1980263363Semaste } 1981263363Semaste if (!cm) 1982263363Semaste mfi_enqueue_bio(sc, bio); 1983263363Semaste return cm; 1984263363Semaste} 1985269024Semastestatic struct mfi_command * 1986269024Semastemfi_build_syspdio(struct mfi_softc *sc, struct bio *bio) 1987263363Semaste{ 1988263363Semaste struct mfi_command *cm; 1989263363Semaste struct mfi_pass_frame *pass; 1990263363Semaste int flags = 0, blkcount = 0; 1991263363Semaste uint32_t context = 0; 1992263363Semaste 1993263363Semaste if ((cm = mfi_dequeue_free(sc)) == NULL) 1994263363Semaste return (NULL); 1995269024Semaste 1996269024Semaste /* Zero out the MFI frame */ 1997263363Semaste context = cm->cm_frame->header.context; 1998263363Semaste bzero(cm->cm_frame, sizeof(union mfi_frame)); 1999263363Semaste cm->cm_frame->header.context = context; 2000263363Semaste pass = &cm->cm_frame->pass; 2001263363Semaste bzero(pass->cdb, 16); 2002263363Semaste pass->header.cmd = MFI_CMD_PD_SCSI_IO; 2003263363Semaste switch (bio->bio_cmd & 0x03) { 2004263363Semaste case BIO_READ: 2005263363Semaste#define SCSI_READ 0x28 2006269024Semaste pass->cdb[0] = SCSI_READ; 2007269024Semaste flags = MFI_CMD_DATAIN; 2008263363Semaste break; 2009263363Semaste case BIO_WRITE: 2010263363Semaste#define SCSI_WRITE 0x2a 2011263363Semaste pass->cdb[0] = SCSI_WRITE; 2012263363Semaste flags = MFI_CMD_DATAOUT; 2013263363Semaste break; 2014263363Semaste default: 2015263363Semaste panic("Invalid bio command"); 2016269024Semaste } 2017269024Semaste 2018263363Semaste /* Cheat with the sector length to avoid a non-constant division */ 2019263363Semaste blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2020263363Semaste /* Fill the LBA and Transfer length in CDB */ 2021263363Semaste pass->cdb[2] = (bio->bio_pblkno & 0xff000000) >> 24; 2022263363Semaste pass->cdb[3] = (bio->bio_pblkno & 0x00ff0000) >> 16; 2023263363Semaste pass->cdb[4] = (bio->bio_pblkno & 0x0000ff00) >> 8; 2024263363Semaste pass->cdb[5] = bio->bio_pblkno & 0x000000ff; 2025263363Semaste pass->cdb[7] = (blkcount & 0xff00) >> 8; 2026263363Semaste pass->cdb[8] = (blkcount & 0x00ff); 2027269024Semaste pass->header.target_id = (uintptr_t)bio->bio_driver1; 2028269024Semaste pass->header.timeout = 0; 2029263363Semaste pass->header.flags = 0; 2030263363Semaste pass->header.scsi_status = 0; 2031263363Semaste pass->header.sense_len = MFI_SENSE_LEN; 2032263363Semaste pass->header.data_len = bio->bio_bcount; 2033263363Semaste pass->header.cdb_len = 10; 2034263363Semaste pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2035263363Semaste pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2036263363Semaste cm->cm_complete = mfi_bio_complete; 2037263363Semaste cm->cm_private = bio; 2038263363Semaste cm->cm_data = bio->bio_data; 2039263363Semaste cm->cm_len = bio->bio_bcount; 2040263363Semaste cm->cm_sg = &pass->sgl; 2041263363Semaste cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; 2042263363Semaste cm->cm_flags = flags; 2043263363Semaste return (cm); 2044263363Semaste} 2045263363Semaste 2046263363Semastestatic struct mfi_command * 2047263363Semastemfi_build_ldio(struct mfi_softc *sc, struct bio *bio) 2048263363Semaste{ 2049263363Semaste struct mfi_io_frame *io; 2050263363Semaste struct mfi_command *cm; 2051263363Semaste int flags, blkcount; 2052263363Semaste uint32_t context = 0; 2053263363Semaste 2054263363Semaste if ((cm = mfi_dequeue_free(sc)) == NULL) 2055263363Semaste return (NULL); 2056263363Semaste 2057263363Semaste /* Zero out the MFI frame */ 2058263363Semaste context = cm->cm_frame->header.context; 2059263363Semaste bzero(cm->cm_frame, sizeof(union mfi_frame)); 2060263363Semaste cm->cm_frame->header.context = context; 2061263363Semaste io = &cm->cm_frame->io; 2062263363Semaste switch (bio->bio_cmd & 0x03) { 2063263363Semaste case BIO_READ: 2064263363Semaste io->header.cmd = MFI_CMD_LD_READ; 2065263363Semaste flags = MFI_CMD_DATAIN; 2066263363Semaste break; 2067263363Semaste case BIO_WRITE: 2068263363Semaste io->header.cmd = MFI_CMD_LD_WRITE; 2069263363Semaste flags = MFI_CMD_DATAOUT; 2070263363Semaste break; 2071263363Semaste default: 2072263363Semaste panic("Invalid bio command"); 2073263363Semaste } 2074263363Semaste 2075263363Semaste /* Cheat with the sector length to avoid a non-constant division */ 2076263363Semaste blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2077263363Semaste io->header.target_id = (uintptr_t)bio->bio_driver1; 2078263363Semaste io->header.timeout = 0; 2079263363Semaste io->header.flags = 0; 2080263363Semaste io->header.scsi_status = 0; 2081263363Semaste io->header.sense_len = MFI_SENSE_LEN; 2082263363Semaste io->header.data_len = blkcount; 2083263363Semaste io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2084263363Semaste io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2085263363Semaste io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32; 2086263363Semaste io->lba_lo = bio->bio_pblkno & 0xffffffff; 2087263363Semaste cm->cm_complete = mfi_bio_complete; 2088263363Semaste cm->cm_private = bio; 2089263363Semaste cm->cm_data = bio->bio_data; 2090263363Semaste cm->cm_len = bio->bio_bcount; 2091263363Semaste cm->cm_sg = &io->sgl; 2092263363Semaste cm->cm_total_frame_size = MFI_IO_FRAME_SIZE; 2093263363Semaste cm->cm_flags = flags; 2094263363Semaste return (cm); 2095263363Semaste} 2096263363Semaste 2097263363Semastestatic void 2098263363Semastemfi_bio_complete(struct mfi_command *cm) 2099263363Semaste{ 2100263363Semaste struct bio *bio; 2101263363Semaste struct mfi_frame_header *hdr; 2102263363Semaste struct mfi_softc *sc; 2103263363Semaste 2104263363Semaste bio = cm->cm_private; 2105263363Semaste hdr = &cm->cm_frame->header; 2106263363Semaste sc = cm->cm_sc; 2107263363Semaste 2108263363Semaste if ((hdr->cmd_status != MFI_STAT_OK) || (hdr->scsi_status != 0)) { 2109263363Semaste bio->bio_flags |= BIO_ERROR; 2110263363Semaste bio->bio_error = EIO; 2111263363Semaste device_printf(sc->mfi_dev, "I/O error, status= %d " 2112263363Semaste "scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status); 2113263363Semaste mfi_print_sense(cm->cm_sc, cm->cm_sense); 2114263363Semaste } else if (cm->cm_error != 0) { 2115263363Semaste bio->bio_flags |= BIO_ERROR; 2116263363Semaste } 2117263363Semaste 2118263363Semaste mfi_release_command(cm); 2119263363Semaste mfi_disk_complete(bio); 2120263363Semaste} 2121263363Semaste 2122263363Semastevoid 2123263363Semastemfi_startio(struct mfi_softc *sc) 2124263363Semaste{ 2125263363Semaste struct mfi_command *cm; 2126263363Semaste struct ccb_hdr *ccbh; 2127263363Semaste 2128263363Semaste for (;;) { 2129263363Semaste /* Don't bother if we're short on resources */ 2130263363Semaste if (sc->mfi_flags & MFI_FLAGS_QFRZN) 2131263363Semaste break; 2132263363Semaste 2133263363Semaste /* Try a command that has already been prepared */ 2134263363Semaste cm = mfi_dequeue_ready(sc); 2135263363Semaste 2136263363Semaste if (cm == NULL) { 2137263363Semaste if ((ccbh = TAILQ_FIRST(&sc->mfi_cam_ccbq)) != NULL) 2138263363Semaste cm = sc->mfi_cam_start(ccbh); 2139263363Semaste } 2140263363Semaste 2141263363Semaste /* Nope, so look for work on the bioq */ 2142263363Semaste if (cm == NULL) 2143263363Semaste cm = mfi_bio_command(sc); 2144263363Semaste 2145263363Semaste /* No work available, so exit */ 2146263363Semaste if (cm == NULL) 2147263363Semaste break; 2148263363Semaste 2149263363Semaste /* Send the command to the controller */ 2150263363Semaste if (mfi_mapcmd(sc, cm) != 0) { 2151263363Semaste mfi_requeue_ready(cm); 2152263363Semaste break; 2153263363Semaste } 2154263363Semaste } 2155263363Semaste} 2156269024Semaste 2157269024Semasteint 2158263363Semastemfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm) 2159263363Semaste{ 2160263363Semaste int error, polled; 2161263363Semaste 2162263363Semaste mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2163263363Semaste 2164263363Semaste if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) { 2165263363Semaste polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0; 2166263363Semaste error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap, 2167263363Semaste cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled); 2168263363Semaste if (error == EINPROGRESS) { 2169263363Semaste sc->mfi_flags |= MFI_FLAGS_QFRZN; 2170263363Semaste return (0); 2171263363Semaste } 2172263363Semaste } else { 2173263363Semaste if (sc->MFA_enabled) 2174263363Semaste error = mfi_tbolt_send_frame(sc, cm); 2175263363Semaste else 2176263363Semaste error = mfi_send_frame(sc, cm); 2177263363Semaste } 2178263363Semaste 2179263363Semaste return (error); 2180263363Semaste} 2181263363Semaste 2182263363Semastestatic void 2183263363Semastemfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 2184263363Semaste{ 2185263363Semaste struct mfi_frame_header *hdr; 2186263363Semaste struct mfi_command *cm; 2187263363Semaste union mfi_sgl *sgl; 2188263363Semaste struct mfi_softc *sc; 2189263363Semaste int i, j, first, dir; 2190269024Semaste int sge_size; 2191269024Semaste 2192263363Semaste cm = (struct mfi_command *)arg; 2193263363Semaste sc = cm->cm_sc; 2194263363Semaste hdr = &cm->cm_frame->header; 2195263363Semaste sgl = cm->cm_sg; 2196263363Semaste 2197263363Semaste if (error) { 2198263363Semaste printf("error %d in callback\n", error); 2199263363Semaste cm->cm_error = error; 2200263363Semaste mfi_complete(sc, cm); 2201263363Semaste return; 2202263363Semaste } 2203263363Semaste /* Use IEEE sgl only for IO's on a SKINNY controller 2204263363Semaste * For other commands on a SKINNY controller use either 2205263363Semaste * sg32 or sg64 based on the sizeof(bus_addr_t). 2206263363Semaste * Also calculate the total frame size based on the type 2207269024Semaste * of SGL used. 2208269024Semaste */ 2209263363Semaste if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) || 2210263363Semaste (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) || 2211263363Semaste (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) && 2212263363Semaste (sc->mfi_flags & MFI_FLAGS_SKINNY)) { 2213263363Semaste for (i = 0; i < nsegs; i++) { 2214263363Semaste sgl->sg_skinny[i].addr = segs[i].ds_addr; 2215263363Semaste sgl->sg_skinny[i].len = segs[i].ds_len; 2216263363Semaste sgl->sg_skinny[i].flag = 0; 2217263363Semaste } 2218263363Semaste hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64; 2219263363Semaste sge_size = sizeof(struct mfi_sg_skinny); 2220263363Semaste hdr->sg_count = nsegs; 2221263363Semaste } else { 2222263363Semaste j = 0; 2223263363Semaste if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 2224263363Semaste first = cm->cm_stp_len; 2225263363Semaste if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { 2226263363Semaste sgl->sg32[j].addr = segs[0].ds_addr; 2227263363Semaste sgl->sg32[j++].len = first; 2228263363Semaste } else { 2229263363Semaste sgl->sg64[j].addr = segs[0].ds_addr; 2230263363Semaste sgl->sg64[j++].len = first; 2231263363Semaste } 2232263363Semaste } else 2233263363Semaste first = 0; 2234263363Semaste if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) { 2235263363Semaste for (i = 0; i < nsegs; i++) { 2236263363Semaste sgl->sg32[j].addr = segs[i].ds_addr + first; 2237263363Semaste sgl->sg32[j++].len = segs[i].ds_len - first; 2238263363Semaste first = 0; 2239263363Semaste } 2240263363Semaste } else { 2241263363Semaste for (i = 0; i < nsegs; i++) { 2242263363Semaste sgl->sg64[j].addr = segs[i].ds_addr + first; 2243263363Semaste sgl->sg64[j++].len = segs[i].ds_len - first; 2244269024Semaste first = 0; 2245269024Semaste } 2246263363Semaste hdr->flags |= MFI_FRAME_SGL64; 2247263363Semaste } 2248263363Semaste hdr->sg_count = j; 2249263363Semaste sge_size = sc->mfi_sge_size; 2250263363Semaste } 2251263363Semaste 2252263363Semaste dir = 0; 2253263363Semaste if (cm->cm_flags & MFI_CMD_DATAIN) { 2254263363Semaste dir |= BUS_DMASYNC_PREREAD; 2255269024Semaste hdr->flags |= MFI_FRAME_DIR_READ; 2256269024Semaste } 2257263363Semaste if (cm->cm_flags & MFI_CMD_DATAOUT) { 2258263363Semaste dir |= BUS_DMASYNC_PREWRITE; 2259263363Semaste hdr->flags |= MFI_FRAME_DIR_WRITE; 2260263363Semaste } 2261263363Semaste bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir); 2262263363Semaste cm->cm_flags |= MFI_CMD_MAPPED; 2263263363Semaste 2264263363Semaste /* 2265263363Semaste * Instead of calculating the total number of frames in the 2266263363Semaste * compound frame, it's already assumed that there will be at 2267263363Semaste * least 1 frame, so don't compensate for the modulo of the 2268263363Semaste * following division. 2269263363Semaste */ 2270263363Semaste cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs); 2271263363Semaste cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; 2272263363Semaste 2273263363Semaste if (sc->MFA_enabled) 2274263363Semaste mfi_tbolt_send_frame(sc, cm); 2275263363Semaste else 2276263363Semaste mfi_send_frame(sc, cm); 2277263363Semaste 2278269024Semaste return; 2279269024Semaste} 2280263363Semaste 2281263363Semastestatic int 2282263363Semastemfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm) 2283263363Semaste{ 2284263363Semaste struct mfi_frame_header *hdr; 2285263363Semaste int tm = MFI_POLL_TIMEOUT_SECS * 1000; 2286263363Semaste 2287263363Semaste hdr = &cm->cm_frame->header; 2288263363Semaste 2289263363Semaste if ((cm->cm_flags & MFI_CMD_POLLED) == 0) { 2290263363Semaste cm->cm_timestamp = time_uptime; 2291263363Semaste mfi_enqueue_busy(cm); 2292263363Semaste } else { 2293263363Semaste hdr->cmd_status = MFI_STAT_INVALID_STATUS; 2294263363Semaste hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 2295263363Semaste } 2296263363Semaste 2297263363Semaste /* 2298263363Semaste * The bus address of the command is aligned on a 64 byte boundary, 2299263363Semaste * leaving the least 6 bits as zero. For whatever reason, the 2300263363Semaste * hardware wants the address shifted right by three, leaving just 2301263363Semaste * 3 zero bits. These three bits are then used as a prefetching 2302263363Semaste * hint for the hardware to predict how many frames need to be 2303263363Semaste * fetched across the bus. If a command has more than 8 frames 2304263363Semaste * then the 3 bits are set to 0x7 and the firmware uses other 2305263363Semaste * information in the command to determine the total amount to fetch. 2306263363Semaste * However, FreeBSD doesn't support I/O larger than 128K, so 8 frames 2307263363Semaste * is enough for both 32bit and 64bit systems. 2308263363Semaste */ 2309263363Semaste if (cm->cm_extra_frames > 7) 2310263363Semaste cm->cm_extra_frames = 7; 2311263363Semaste 2312263363Semaste sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames); 2313263363Semaste 2314263363Semaste if ((cm->cm_flags & MFI_CMD_POLLED) == 0) 2315263363Semaste return (0); 2316269024Semaste 2317263363Semaste /* This is a polled command, so busy-wait for it to complete. */ 2318263363Semaste while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 2319263363Semaste DELAY(1000); 2320263363Semaste tm -= 1; 2321263363Semaste if (tm <= 0) 2322263363Semaste break; 2323263363Semaste } 2324263363Semaste 2325263363Semaste if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 2326263363Semaste device_printf(sc->mfi_dev, "Frame %p timed out " 2327263363Semaste "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode); 2328263363Semaste return (ETIMEDOUT); 2329263363Semaste } 2330263363Semaste 2331263363Semaste return (0); 2332263363Semaste} 2333263363Semaste 2334263363Semaste 2335263363Semastevoid 2336263363Semastemfi_complete(struct mfi_softc *sc, struct mfi_command *cm) 2337263363Semaste{ 2338263363Semaste int dir; 2339263363Semaste 2340263363Semaste if ((cm->cm_flags & MFI_CMD_MAPPED) != 0) { 2341263363Semaste dir = 0; 2342263363Semaste if ((cm->cm_flags & MFI_CMD_DATAIN) || 2343263363Semaste (cm->cm_frame->header.cmd == MFI_CMD_STP)) 2344263363Semaste dir |= BUS_DMASYNC_POSTREAD; 2345263363Semaste if (cm->cm_flags & MFI_CMD_DATAOUT) 2346263363Semaste dir |= BUS_DMASYNC_POSTWRITE; 2347263363Semaste 2348263363Semaste bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir); 2349263363Semaste bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2350263363Semaste cm->cm_flags &= ~MFI_CMD_MAPPED; 2351263363Semaste } 2352263363Semaste 2353263363Semaste cm->cm_flags |= MFI_CMD_COMPLETED; 2354263363Semaste 2355263363Semaste if (cm->cm_complete != NULL) 2356263363Semaste cm->cm_complete(cm); 2357263363Semaste else 2358263363Semaste wakeup(cm); 2359263363Semaste} 2360263363Semaste 2361263363Semastestatic int 2362263363Semastemfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort) 2363263363Semaste{ 2364263363Semaste struct mfi_command *cm; 2365263363Semaste struct mfi_abort_frame *abort; 2366263363Semaste int i = 0; 2367263363Semaste uint32_t context = 0; 2368263363Semaste 2369263363Semaste mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2370263363Semaste 2371263363Semaste if ((cm = mfi_dequeue_free(sc)) == NULL) { 2372263363Semaste return (EBUSY); 2373263363Semaste } 2374263363Semaste 2375263363Semaste /* Zero out the MFI frame */ 2376263363Semaste context = cm->cm_frame->header.context; 2377263363Semaste bzero(cm->cm_frame, sizeof(union mfi_frame)); 2378263363Semaste cm->cm_frame->header.context = context; 2379263363Semaste 2380263363Semaste abort = &cm->cm_frame->abort; 2381263363Semaste abort->header.cmd = MFI_CMD_ABORT; 2382263363Semaste abort->header.flags = 0; 2383263363Semaste abort->header.scsi_status = 0; 2384263363Semaste abort->abort_context = cm_abort->cm_frame->header.context; 2385263363Semaste abort->abort_mfi_addr_lo = (uint32_t)cm_abort->cm_frame_busaddr; 2386263363Semaste abort->abort_mfi_addr_hi = 2387263363Semaste (uint32_t)((uint64_t)cm_abort->cm_frame_busaddr >> 32); 2388263363Semaste cm->cm_data = NULL; 2389263363Semaste cm->cm_flags = MFI_CMD_POLLED; 2390263363Semaste 2391263363Semaste if (sc->mfi_aen_cm) 2392263363Semaste sc->cm_aen_abort = 1; 2393263363Semaste if (sc->mfi_map_sync_cm) 2394263363Semaste sc->cm_map_abort = 1; 2395263363Semaste mfi_mapcmd(sc, cm); 2396263363Semaste mfi_release_command(cm); 2397263363Semaste 2398263363Semaste while (i < 5 && sc->mfi_aen_cm != NULL) { 2399269024Semaste msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", 2400269024Semaste 5 * hz); 2401263363Semaste i++; 2402263363Semaste } 2403263363Semaste while (i < 5 && sc->mfi_map_sync_cm != NULL) { 2404263363Semaste msleep(&sc->mfi_map_sync_cm, &sc->mfi_io_lock, 0, "mfiabort", 2405263363Semaste 5 * hz); 2406263363Semaste i++; 2407263363Semaste } 2408263363Semaste 2409263363Semaste return (0); 2410263363Semaste} 2411263363Semaste 2412263363Semasteint 2413263363Semastemfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, 2414263363Semaste int len) 2415263363Semaste{ 2416263363Semaste struct mfi_command *cm; 2417263363Semaste struct mfi_io_frame *io; 2418263363Semaste int error; 2419263363Semaste uint32_t context = 0; 2420263363Semaste 2421263363Semaste if ((cm = mfi_dequeue_free(sc)) == NULL) 2422263363Semaste return (EBUSY); 2423263363Semaste 2424263363Semaste /* Zero out the MFI frame */ 2425263363Semaste context = cm->cm_frame->header.context; 2426263363Semaste bzero(cm->cm_frame, sizeof(union mfi_frame)); 2427263363Semaste cm->cm_frame->header.context = context; 2428263363Semaste 2429263363Semaste io = &cm->cm_frame->io; 2430263363Semaste io->header.cmd = MFI_CMD_LD_WRITE; 2431263363Semaste io->header.target_id = id; 2432263363Semaste io->header.timeout = 0; 2433263363Semaste io->header.flags = 0; 2434263363Semaste io->header.scsi_status = 0; 2435263363Semaste io->header.sense_len = MFI_SENSE_LEN; 2436263363Semaste io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2437263363Semaste io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2438263363Semaste io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2439263363Semaste io->lba_hi = (lba & 0xffffffff00000000) >> 32; 2440263363Semaste io->lba_lo = lba & 0xffffffff; 2441263363Semaste cm->cm_data = virt; 2442263363Semaste cm->cm_len = len; 2443263363Semaste cm->cm_sg = &io->sgl; 2444263363Semaste cm->cm_total_frame_size = MFI_IO_FRAME_SIZE; 2445263363Semaste cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT; 2446263363Semaste 2447263363Semaste error = mfi_mapcmd(sc, cm); 2448263363Semaste bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 2449263363Semaste BUS_DMASYNC_POSTWRITE); 2450263363Semaste bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2451263363Semaste mfi_release_command(cm); 2452263363Semaste 2453263363Semaste return (error); 2454263363Semaste} 2455263363Semaste 2456263363Semasteint 2457263363Semastemfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, 2458263363Semaste int len) 2459263363Semaste{ 2460263363Semaste struct mfi_command *cm; 2461263363Semaste struct mfi_pass_frame *pass; 2462263363Semaste int error; 2463263363Semaste int blkcount = 0; 2464263363Semaste 2465263363Semaste if ((cm = mfi_dequeue_free(sc)) == NULL) 2466263363Semaste return (EBUSY); 2467263363Semaste 2468263363Semaste pass = &cm->cm_frame->pass; 2469263363Semaste bzero(pass->cdb, 16); 2470263363Semaste pass->header.cmd = MFI_CMD_PD_SCSI_IO; 2471263363Semaste pass->cdb[0] = SCSI_WRITE; 2472263363Semaste pass->cdb[2] = (lba & 0xff000000) >> 24; 2473263363Semaste pass->cdb[3] = (lba & 0x00ff0000) >> 16; 2474263363Semaste pass->cdb[4] = (lba & 0x0000ff00) >> 8; 2475263363Semaste pass->cdb[5] = (lba & 0x000000ff); 2476263363Semaste blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN; 2477263363Semaste pass->cdb[7] = (blkcount & 0xff00) >> 8; 2478269024Semaste pass->cdb[8] = (blkcount & 0x00ff); 2479269024Semaste pass->header.target_id = id; 2480269024Semaste pass->header.timeout = 0; 2481269024Semaste pass->header.flags = 0; 2482269024Semaste pass->header.scsi_status = 0; 2483269024Semaste pass->header.sense_len = MFI_SENSE_LEN; 2484269024Semaste pass->header.data_len = len; 2485269024Semaste pass->header.cdb_len = 10; 2486269024Semaste pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr; 2487269024Semaste pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 2488269024Semaste cm->cm_data = virt; 2489269024Semaste cm->cm_len = len; 2490263363Semaste cm->cm_sg = &pass->sgl; 2491263363Semaste cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE; 2492263363Semaste cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT; 2493263363Semaste 2494263363Semaste error = mfi_mapcmd(sc, cm); 2495263363Semaste bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, 2496263363Semaste BUS_DMASYNC_POSTWRITE); 2497263363Semaste bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap); 2498263363Semaste mfi_release_command(cm); 2499263363Semaste 2500263363Semaste return (error); 2501263363Semaste} 2502263363Semaste 2503263363Semastestatic int 2504263363Semastemfi_open(struct cdev *dev, int flags, int fmt, struct thread *td) 2505263363Semaste{ 2506263363Semaste struct mfi_softc *sc; 2507263363Semaste int error; 2508263363Semaste 2509263363Semaste sc = dev->si_drv1; 2510263363Semaste 2511263363Semaste mtx_lock(&sc->mfi_io_lock); 2512263363Semaste if (sc->mfi_detaching) 2513263363Semaste error = ENXIO; 2514263363Semaste else { 2515263363Semaste sc->mfi_flags |= MFI_FLAGS_OPEN; 2516263363Semaste error = 0; 2517263363Semaste } 2518263363Semaste mtx_unlock(&sc->mfi_io_lock); 2519263363Semaste 2520263363Semaste return (error); 2521263363Semaste} 2522263363Semaste 2523263363Semastestatic int 2524263363Semastemfi_close(struct cdev *dev, int flags, int fmt, struct thread *td) 2525263363Semaste{ 2526263363Semaste struct mfi_softc *sc; 2527263363Semaste struct mfi_aen *mfi_aen_entry, *tmp; 2528263363Semaste 2529263363Semaste sc = dev->si_drv1; 2530263363Semaste 2531263363Semaste mtx_lock(&sc->mfi_io_lock); 2532263363Semaste sc->mfi_flags &= ~MFI_FLAGS_OPEN; 2533263363Semaste 2534263363Semaste TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) { 2535263363Semaste if (mfi_aen_entry->p == curproc) { 2536263363Semaste TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 2537263363Semaste aen_link); 2538263363Semaste free(mfi_aen_entry, M_MFIBUF); 2539263363Semaste } 2540263363Semaste } 2541263363Semaste mtx_unlock(&sc->mfi_io_lock); 2542263363Semaste return (0); 2543263363Semaste} 2544263363Semaste 2545263363Semastestatic int 2546263363Semastemfi_config_lock(struct mfi_softc *sc, uint32_t opcode) 2547263363Semaste{ 2548263363Semaste 2549263363Semaste switch (opcode) { 2550263363Semaste case MFI_DCMD_LD_DELETE: 2551263363Semaste case MFI_DCMD_CFG_ADD: 2552263363Semaste case MFI_DCMD_CFG_CLEAR: 2553263363Semaste case MFI_DCMD_CFG_FOREIGN_IMPORT: 2554263363Semaste sx_xlock(&sc->mfi_config_lock); 2555263363Semaste return (1); 2556263363Semaste default: 2557263363Semaste return (0); 2558263363Semaste } 2559263363Semaste} 2560263363Semaste 2561263363Semastestatic void 2562263363Semastemfi_config_unlock(struct mfi_softc *sc, int locked) 2563263363Semaste{ 2564263363Semaste 2565263363Semaste if (locked) 2566263363Semaste sx_xunlock(&sc->mfi_config_lock); 2567263363Semaste} 2568263363Semaste 2569263363Semaste/* 2570263363Semaste * Perform pre-issue checks on commands from userland and possibly veto 2571263363Semaste * them. 2572263363Semaste */ 2573263363Semastestatic int 2574263363Semastemfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm) 2575263363Semaste{ 2576263363Semaste struct mfi_disk *ld, *ld2; 2577263363Semaste int error; 2578263363Semaste struct mfi_system_pd *syspd = NULL; 2579263363Semaste uint16_t syspd_id; 2580263363Semaste uint16_t *mbox; 2581263363Semaste 2582263363Semaste mtx_assert(&sc->mfi_io_lock, MA_OWNED); 2583263363Semaste error = 0; 2584263363Semaste switch (cm->cm_frame->dcmd.opcode) { 2585263363Semaste case MFI_DCMD_LD_DELETE: 2586263363Semaste TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2587263363Semaste if (ld->ld_id == cm->cm_frame->dcmd.mbox[0]) 2588263363Semaste break; 2589263363Semaste } 2590263363Semaste if (ld == NULL) 2591263363Semaste error = ENOENT; 2592263363Semaste else 2593263363Semaste error = mfi_disk_disable(ld); 2594263363Semaste break; 2595263363Semaste case MFI_DCMD_CFG_CLEAR: 2596263363Semaste TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2597263363Semaste error = mfi_disk_disable(ld); 2598263363Semaste if (error) 2599263363Semaste break; 2600263363Semaste } 2601263363Semaste if (error) { 2602263363Semaste TAILQ_FOREACH(ld2, &sc->mfi_ld_tqh, ld_link) { 2603263363Semaste if (ld2 == ld) 2604263363Semaste break; 2605263363Semaste mfi_disk_enable(ld2); 2606263363Semaste } 2607263363Semaste } 2608263363Semaste break; 2609263363Semaste case MFI_DCMD_PD_STATE_SET: 2610263363Semaste mbox = (uint16_t *) cm->cm_frame->dcmd.mbox; 2611263363Semaste syspd_id = mbox[0]; 2612263363Semaste if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { 2613263363Semaste TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) { 2614263363Semaste if (syspd->pd_id == syspd_id) 2615263363Semaste break; 2616263363Semaste } 2617263363Semaste } 2618263363Semaste else 2619263363Semaste break; 2620263363Semaste if (syspd) 2621263363Semaste error = mfi_syspd_disable(syspd); 2622263363Semaste break; 2623263363Semaste default: 2624263363Semaste break; 2625263363Semaste } 2626263363Semaste return (error); 2627263363Semaste} 2628263363Semaste 2629263363Semaste/* Perform post-issue checks on commands from userland. */ 2630263363Semastestatic void 2631263363Semastemfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm) 2632263363Semaste{ 2633263363Semaste struct mfi_disk *ld, *ldn; 2634269024Semaste struct mfi_system_pd *syspd = NULL; 2635269024Semaste uint16_t syspd_id; 2636263363Semaste uint16_t *mbox; 2637263363Semaste 2638263363Semaste switch (cm->cm_frame->dcmd.opcode) { 2639263363Semaste case MFI_DCMD_LD_DELETE: 2640263363Semaste TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2641263363Semaste if (ld->ld_id == cm->cm_frame->dcmd.mbox[0]) 2642263363Semaste break; 2643263363Semaste } 2644263363Semaste KASSERT(ld != NULL, ("volume dissappeared")); 2645263363Semaste if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { 2646263363Semaste mtx_unlock(&sc->mfi_io_lock); 2647263363Semaste mtx_lock(&Giant); 2648263363Semaste device_delete_child(sc->mfi_dev, ld->ld_dev); 2649263363Semaste mtx_unlock(&Giant); 2650263363Semaste mtx_lock(&sc->mfi_io_lock); 2651263363Semaste } else 2652263363Semaste mfi_disk_enable(ld); 2653263363Semaste break; 2654263363Semaste case MFI_DCMD_CFG_CLEAR: 2655263363Semaste if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { 2656263363Semaste mtx_unlock(&sc->mfi_io_lock); 2657263363Semaste mtx_lock(&Giant); 2658263363Semaste TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) { 2659263363Semaste device_delete_child(sc->mfi_dev, ld->ld_dev); 2660263363Semaste } 2661263363Semaste mtx_unlock(&Giant); 2662263363Semaste mtx_lock(&sc->mfi_io_lock); 2663263363Semaste } else { 2664263363Semaste TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) 2665263363Semaste mfi_disk_enable(ld); 2666263363Semaste } 2667263363Semaste break; 2668263363Semaste case MFI_DCMD_CFG_ADD: 2669263363Semaste mfi_ldprobe(sc); 2670263363Semaste break; 2671263363Semaste case MFI_DCMD_CFG_FOREIGN_IMPORT: 2672263363Semaste mfi_ldprobe(sc); 2673263363Semaste break; 2674263363Semaste case MFI_DCMD_PD_STATE_SET: 2675263363Semaste mbox = (uint16_t *) cm->cm_frame->dcmd.mbox; 2676263363Semaste syspd_id = mbox[0]; 2677263363Semaste if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) { 2678263363Semaste TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) { 2679263363Semaste if (syspd->pd_id == syspd_id) 2680263363Semaste break; 2681263363Semaste } 2682263363Semaste } 2683263363Semaste else 2684263363Semaste break; 2685263363Semaste /* If the transition fails then enable the syspd again */ 2686263363Semaste if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK) 2687263363Semaste mfi_syspd_enable(syspd); 2688263363Semaste break; 2689263363Semaste } 2690263363Semaste} 2691263363Semaste 2692263363Semastestatic int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm) 2693263363Semaste{ 2694263363Semaste struct mfi_config_data *conf_data=(struct mfi_config_data *)cm->cm_data; 2695263363Semaste struct mfi_command *ld_cm = NULL; 2696263363Semaste struct mfi_ld_info *ld_info = NULL; 2697263363Semaste int error = 0; 2698263363Semaste 2699263363Semaste if ((cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) && 2700263363Semaste (conf_data->ld[0].params.isSSCD == 1)) { 2701263363Semaste error = 1; 2702263363Semaste } else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) { 2703263363Semaste error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO, 2704263363Semaste (void **)&ld_info, sizeof(*ld_info)); 2705263363Semaste if (error) { 2706263363Semaste device_printf(sc->mfi_dev, "Failed to allocate" 2707263363Semaste "MFI_DCMD_LD_GET_INFO %d", error); 2708263363Semaste if (ld_info) 2709263363Semaste free(ld_info, M_MFIBUF); 2710263363Semaste return 0; 2711263363Semaste } 2712263363Semaste ld_cm->cm_flags = MFI_CMD_DATAIN; 2713263363Semaste ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0]; 2714263363Semaste ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0]; 2715263363Semaste if (mfi_wait_command(sc, ld_cm) != 0) { 2716263363Semaste device_printf(sc->mfi_dev, "failed to get log drv\n"); 2717263363Semaste mfi_release_command(ld_cm); 2718263363Semaste free(ld_info, M_MFIBUF); 2719263363Semaste return 0; 2720263363Semaste } 2721263363Semaste 2722263363Semaste if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) { 2723263363Semaste free(ld_info, M_MFIBUF); 2724263363Semaste mfi_release_command(ld_cm); 2725263363Semaste return 0; 2726263363Semaste } 2727263363Semaste else 2728263363Semaste ld_info = (struct mfi_ld_info *)ld_cm->cm_private; 2729263363Semaste 2730263363Semaste if (ld_info->ld_config.params.isSSCD == 1) 2731263363Semaste error = 1; 2732263363Semaste 2733263363Semaste mfi_release_command(ld_cm); 2734263363Semaste free(ld_info, M_MFIBUF); 2735263363Semaste 2736263363Semaste } 2737263363Semaste return error; 2738263363Semaste} 2739263363Semaste 2740263363Semastestatic int 2741263363Semastemfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg) 2742263363Semaste{ 2743263363Semaste uint8_t i; 2744263363Semaste struct mfi_ioc_packet *ioc; 2745263363Semaste ioc = (struct mfi_ioc_packet *)arg; 2746263363Semaste int sge_size, error; 2747263363Semaste struct megasas_sge *kern_sge; 2748263363Semaste 2749263363Semaste memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr)); 2750263363Semaste kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off); 2751263363Semaste cm->cm_frame->header.sg_count = ioc->mfi_sge_count; 2752263363Semaste 2753263363Semaste if (sizeof(bus_addr_t) == 8) { 2754263363Semaste cm->cm_frame->header.flags |= MFI_FRAME_SGL64; 2755263363Semaste cm->cm_extra_frames = 2; 2756263363Semaste sge_size = sizeof(struct mfi_sg64); 2757263363Semaste } else { 2758263363Semaste cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE; 2759263363Semaste sge_size = sizeof(struct mfi_sg32); 2760263363Semaste } 2761263363Semaste 2762263363Semaste cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count); 2763263363Semaste for (i = 0; i < ioc->mfi_sge_count; i++) { 2764263363Semaste if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */ 2765263363Semaste 1, 0, /* algnmnt, boundary */ 2766263363Semaste BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 2767263363Semaste BUS_SPACE_MAXADDR, /* highaddr */ 2768263363Semaste NULL, NULL, /* filter, filterarg */ 2769263363Semaste ioc->mfi_sgl[i].iov_len,/* maxsize */ 2770263363Semaste 2, /* nsegments */ 2771263363Semaste ioc->mfi_sgl[i].iov_len,/* maxsegsize */ 2772263363Semaste BUS_DMA_ALLOCNOW, /* flags */ 2773263363Semaste NULL, NULL, /* lockfunc, lockarg */ 2774263363Semaste &sc->mfi_kbuff_arr_dmat[i])) { 2775263363Semaste device_printf(sc->mfi_dev, 2776263363Semaste "Cannot allocate mfi_kbuff_arr_dmat tag\n"); 2777263363Semaste return (ENOMEM); 2778263363Semaste } 2779263363Semaste 2780263363Semaste if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i], 2781263363Semaste (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT, 2782263363Semaste &sc->mfi_kbuff_arr_dmamap[i])) { 2783263363Semaste device_printf(sc->mfi_dev, 2784263363Semaste "Cannot allocate mfi_kbuff_arr_dmamap memory\n"); 2785263363Semaste return (ENOMEM); 2786263363Semaste } 2787263363Semaste 2788263363Semaste bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i], 2789263363Semaste sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i], 2790263363Semaste ioc->mfi_sgl[i].iov_len, mfi_addr_cb, 2791263363Semaste &sc->mfi_kbuff_arr_busaddr[i], 0); 2792263363Semaste 2793263363Semaste if (!sc->kbuff_arr[i]) { 2794263363Semaste device_printf(sc->mfi_dev, 2795263363Semaste "Could not allocate memory for kbuff_arr info\n"); 2796263363Semaste return -1; 2797263363Semaste } 2798263363Semaste kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i]; 2799263363Semaste kern_sge[i].length = ioc->mfi_sgl[i].iov_len; 2800263363Semaste 2801263363Semaste if (sizeof(bus_addr_t) == 8) { 2802263363Semaste cm->cm_frame->stp.sgl.sg64[i].addr = 2803263363Semaste kern_sge[i].phys_addr; 2804263363Semaste cm->cm_frame->stp.sgl.sg64[i].len = 2805263363Semaste ioc->mfi_sgl[i].iov_len; 2806263363Semaste } else { 2807263363Semaste cm->cm_frame->stp.sgl.sg32[i].len = 2808263363Semaste kern_sge[i].phys_addr; 2809263363Semaste cm->cm_frame->stp.sgl.sg32[i].len = 2810263363Semaste ioc->mfi_sgl[i].iov_len; 2811263363Semaste } 2812263363Semaste 2813263363Semaste error = copyin(ioc->mfi_sgl[i].iov_base, 2814263363Semaste sc->kbuff_arr[i], 2815263363Semaste ioc->mfi_sgl[i].iov_len); 2816263363Semaste if (error != 0) { 2817263363Semaste device_printf(sc->mfi_dev, "Copy in failed\n"); 2818263363Semaste return error; 2819263363Semaste } 2820263363Semaste } 2821263363Semaste 2822263363Semaste cm->cm_flags |=MFI_CMD_MAPPED; 2823263363Semaste return 0; 2824263363Semaste} 2825263363Semaste 2826263363Semastestatic int 2827263363Semastemfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc) 2828263363Semaste{ 2829263363Semaste struct mfi_command *cm; 2830263363Semaste struct mfi_dcmd_frame *dcmd; 2831263363Semaste void *ioc_buf = NULL; 2832263363Semaste uint32_t context; 2833263363Semaste int error = 0, locked; 2834263363Semaste 2835263363Semaste 2836263363Semaste if (ioc->buf_size > 0) { 2837263363Semaste if (ioc->buf_size > 1024 * 1024) 2838263363Semaste return (ENOMEM); 2839263363Semaste ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK); 2840263363Semaste error = copyin(ioc->buf, ioc_buf, ioc->buf_size); 2841263363Semaste if (error) { 2842263363Semaste device_printf(sc->mfi_dev, "failed to copyin\n"); 2843263363Semaste free(ioc_buf, M_MFIBUF); 2844263363Semaste return (error); 2845269024Semaste } 2846269024Semaste } 2847263363Semaste 2848263363Semaste locked = mfi_config_lock(sc, ioc->ioc_frame.opcode); 2849263363Semaste 2850263363Semaste mtx_lock(&sc->mfi_io_lock); 2851263363Semaste while ((cm = mfi_dequeue_free(sc)) == NULL) 2852263363Semaste msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz); 2853263363Semaste 2854263363Semaste /* Save context for later */ 2855263363Semaste context = cm->cm_frame->header.context; 2856263363Semaste 2857263363Semaste dcmd = &cm->cm_frame->dcmd; 2858263363Semaste bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame)); 2859263363Semaste 2860263363Semaste cm->cm_sg = &dcmd->sgl; 2861263363Semaste cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 2862263363Semaste cm->cm_data = ioc_buf; 2863263363Semaste cm->cm_len = ioc->buf_size; 2864263363Semaste 2865263363Semaste /* restore context */ 2866263363Semaste cm->cm_frame->header.context = context; 2867263363Semaste 2868263363Semaste /* Cheat since we don't know if we're writing or reading */ 2869263363Semaste cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT; 2870263363Semaste 2871263363Semaste error = mfi_check_command_pre(sc, cm); 2872263363Semaste if (error) 2873263363Semaste goto out; 2874263363Semaste 2875263363Semaste error = mfi_wait_command(sc, cm); 2876263363Semaste if (error) { 2877263363Semaste device_printf(sc->mfi_dev, "ioctl failed %d\n", error); 2878263363Semaste goto out; 2879263363Semaste } 2880263363Semaste bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame)); 2881263363Semaste mfi_check_command_post(sc, cm); 2882263363Semasteout: 2883263363Semaste mfi_release_command(cm); 2884263363Semaste mtx_unlock(&sc->mfi_io_lock); 2885263363Semaste mfi_config_unlock(sc, locked); 2886263363Semaste if (ioc->buf_size > 0) 2887263363Semaste error = copyout(ioc_buf, ioc->buf, ioc->buf_size); 2888263363Semaste if (ioc_buf) 2889263363Semaste free(ioc_buf, M_MFIBUF); 2890263363Semaste return (error); 2891263363Semaste} 2892263363Semaste 2893263363Semaste#define PTRIN(p) ((void *)(uintptr_t)(p)) 2894263363Semaste 2895263363Semastestatic int 2896263363Semastemfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 2897263363Semaste{ 2898263363Semaste struct mfi_softc *sc; 2899263363Semaste union mfi_statrequest *ms; 2900263363Semaste struct mfi_ioc_packet *ioc; 2901263363Semaste#ifdef COMPAT_FREEBSD32 2902263363Semaste struct mfi_ioc_packet32 *ioc32; 2903263363Semaste#endif 2904263363Semaste struct mfi_ioc_aen *aen; 2905263363Semaste struct mfi_command *cm = NULL; 2906263363Semaste uint32_t context = 0; 2907263363Semaste union mfi_sense_ptr sense_ptr; 2908263363Semaste uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0; 2909263363Semaste size_t len; 2910263363Semaste int i, res; 2911263363Semaste struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg; 2912263363Semaste#ifdef COMPAT_FREEBSD32 2913263363Semaste struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg; 2914263363Semaste struct mfi_ioc_passthru iop_swab; 2915263363Semaste#endif 2916263363Semaste int error, locked; 2917263363Semaste union mfi_sgl *sgl; 2918263363Semaste sc = dev->si_drv1; 2919263363Semaste error = 0; 2920263363Semaste 2921263363Semaste if (sc->adpreset) 2922263363Semaste return EBUSY; 2923263363Semaste 2924263363Semaste if (sc->hw_crit_error) 2925263363Semaste return EBUSY; 2926263363Semaste 2927263363Semaste if (sc->issuepend_done == 0) 2928263363Semaste return EBUSY; 2929263363Semaste 2930263363Semaste switch (cmd) { 2931263363Semaste case MFIIO_STATS: 2932263363Semaste ms = (union mfi_statrequest *)arg; 2933263363Semaste switch (ms->ms_item) { 2934263363Semaste case MFIQ_FREE: 2935263363Semaste case MFIQ_BIO: 2936263363Semaste case MFIQ_READY: 2937263363Semaste case MFIQ_BUSY: 2938263363Semaste bcopy(&sc->mfi_qstat[ms->ms_item], &ms->ms_qstat, 2939263363Semaste sizeof(struct mfi_qstat)); 2940263363Semaste break; 2941263363Semaste default: 2942263363Semaste error = ENOIOCTL; 2943263363Semaste break; 2944263363Semaste } 2945263363Semaste break; 2946263363Semaste case MFIIO_QUERY_DISK: 2947269024Semaste { 2948269024Semaste struct mfi_query_disk *qd; 2949263363Semaste struct mfi_disk *ld; 2950263363Semaste 2951263363Semaste qd = (struct mfi_query_disk *)arg; 2952263363Semaste mtx_lock(&sc->mfi_io_lock); 2953263363Semaste TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) { 2954263363Semaste if (ld->ld_id == qd->array_id) 2955263363Semaste break; 2956263363Semaste } 2957263363Semaste if (ld == NULL) { 2958263363Semaste qd->present = 0; 2959263363Semaste mtx_unlock(&sc->mfi_io_lock); 2960263363Semaste return (0); 2961263363Semaste } 2962269024Semaste qd->present = 1; 2963269024Semaste if (ld->ld_flags & MFI_DISK_FLAGS_OPEN) 2964263363Semaste qd->open = 1; 2965263363Semaste bzero(qd->devname, SPECNAMELEN + 1); 2966263363Semaste snprintf(qd->devname, SPECNAMELEN, "mfid%d", ld->ld_unit); 2967263363Semaste mtx_unlock(&sc->mfi_io_lock); 2968263363Semaste break; 2969263363Semaste } 2970263363Semaste case MFI_CMD: 2971263363Semaste#ifdef COMPAT_FREEBSD32 2972263363Semaste case MFI_CMD32: 2973263363Semaste#endif 2974263363Semaste { 2975263363Semaste devclass_t devclass; 2976263363Semaste ioc = (struct mfi_ioc_packet *)arg; 2977263363Semaste int adapter; 2978263363Semaste 2979263363Semaste adapter = ioc->mfi_adapter_no; 2980263363Semaste if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) { 2981263363Semaste devclass = devclass_find("mfi"); 2982263363Semaste sc = devclass_get_softc(devclass, adapter); 2983263363Semaste } 2984263363Semaste mtx_lock(&sc->mfi_io_lock); 2985263363Semaste if ((cm = mfi_dequeue_free(sc)) == NULL) { 2986263363Semaste mtx_unlock(&sc->mfi_io_lock); 2987263363Semaste return (EBUSY); 2988263363Semaste } 2989263363Semaste mtx_unlock(&sc->mfi_io_lock); 2990263363Semaste locked = 0; 2991263363Semaste 2992263363Semaste /* 2993263363Semaste * save off original context since copying from user 2994263363Semaste * will clobber some data 2995263363Semaste */ 2996263363Semaste context = cm->cm_frame->header.context; 2997263363Semaste cm->cm_frame->header.context = cm->cm_index; 2998263363Semaste 2999263363Semaste bcopy(ioc->mfi_frame.raw, cm->cm_frame, 3000263363Semaste 2 * MEGAMFI_FRAME_SIZE); 3001263363Semaste cm->cm_total_frame_size = (sizeof(union mfi_sgl) 3002263363Semaste * ioc->mfi_sge_count) + ioc->mfi_sgl_off; 3003263363Semaste cm->cm_frame->header.scsi_status = 0; 3004263363Semaste cm->cm_frame->header.pad0 = 0; 3005263363Semaste if (ioc->mfi_sge_count) { 3006263363Semaste cm->cm_sg = 3007263363Semaste (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off]; 3008263363Semaste } 3009263363Semaste sgl = cm->cm_sg; 3010263363Semaste cm->cm_flags = 0; 3011263363Semaste if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN) 3012263363Semaste cm->cm_flags |= MFI_CMD_DATAIN; 3013263363Semaste if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT) 3014263363Semaste cm->cm_flags |= MFI_CMD_DATAOUT; 3015263363Semaste /* Legacy app shim */ 3016263363Semaste if (cm->cm_flags == 0) 3017263363Semaste cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT; 3018263363Semaste cm->cm_len = cm->cm_frame->header.data_len; 3019263363Semaste if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3020263363Semaste#ifdef COMPAT_FREEBSD32 3021263363Semaste if (cmd == MFI_CMD) { 3022263363Semaste#endif 3023263363Semaste /* Native */ 3024263363Semaste cm->cm_stp_len = ioc->mfi_sgl[0].iov_len; 3025263363Semaste#ifdef COMPAT_FREEBSD32 3026263363Semaste } else { 3027263363Semaste /* 32bit on 64bit */ 3028263363Semaste ioc32 = (struct mfi_ioc_packet32 *)ioc; 3029263363Semaste cm->cm_stp_len = ioc32->mfi_sgl[0].iov_len; 3030263363Semaste } 3031263363Semaste#endif 3032263363Semaste cm->cm_len += cm->cm_stp_len; 3033263363Semaste } 3034269024Semaste if (cm->cm_len && 3035269024Semaste (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) { 3036263363Semaste cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF, 3037263363Semaste M_WAITOK | M_ZERO); 3038263363Semaste if (cm->cm_data == NULL) { 3039263363Semaste device_printf(sc->mfi_dev, "Malloc failed\n"); 3040263363Semaste goto out; 3041263363Semaste } 3042263363Semaste } else { 3043263363Semaste cm->cm_data = 0; 3044263363Semaste } 3045269024Semaste 3046269024Semaste /* restore header context */ 3047263363Semaste cm->cm_frame->header.context = context; 3048263363Semaste 3049263363Semaste if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3050263363Semaste res = mfi_stp_cmd(sc, cm, arg); 3051263363Semaste if (res != 0) 3052263363Semaste goto out; 3053263363Semaste } else { 3054263363Semaste temp = data; 3055263363Semaste if ((cm->cm_flags & MFI_CMD_DATAOUT) || 3056263363Semaste (cm->cm_frame->header.cmd == MFI_CMD_STP)) { 3057263363Semaste for (i = 0; i < ioc->mfi_sge_count; i++) { 3058263363Semaste#ifdef COMPAT_FREEBSD32 3059263363Semaste if (cmd == MFI_CMD) { 3060263363Semaste#endif 3061263363Semaste /* Native */ 3062263363Semaste addr = ioc->mfi_sgl[i].iov_base; 3063263363Semaste len = ioc->mfi_sgl[i].iov_len; 3064263363Semaste#ifdef COMPAT_FREEBSD32 3065263363Semaste } else { 3066263363Semaste /* 32bit on 64bit */ 3067263363Semaste ioc32 = (struct mfi_ioc_packet32 *)ioc; 3068263363Semaste addr = PTRIN(ioc32->mfi_sgl[i].iov_base); 3069263363Semaste len = ioc32->mfi_sgl[i].iov_len; 3070263363Semaste } 3071263363Semaste#endif 3072263363Semaste error = copyin(addr, temp, len); 3073263363Semaste if (error != 0) { 3074263363Semaste device_printf(sc->mfi_dev, 3075263363Semaste "Copy in failed\n"); 3076263363Semaste goto out; 3077263363Semaste } 3078263363Semaste temp = &temp[len]; 3079263363Semaste } 3080263363Semaste } 3081263363Semaste } 3082263363Semaste 3083263363Semaste if (cm->cm_frame->header.cmd == MFI_CMD_DCMD) 3084263363Semaste locked = mfi_config_lock(sc, 3085263363Semaste cm->cm_frame->dcmd.opcode); 3086263363Semaste 3087263363Semaste if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { 3088263363Semaste cm->cm_frame->pass.sense_addr_lo = 3089263363Semaste (uint32_t)cm->cm_sense_busaddr; 3090263363Semaste cm->cm_frame->pass.sense_addr_hi = 3091263363Semaste (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 3092263363Semaste } 3093263363Semaste mtx_lock(&sc->mfi_io_lock); 3094263363Semaste skip_pre_post = mfi_check_for_sscd (sc, cm); 3095263363Semaste if (!skip_pre_post) { 3096263363Semaste error = mfi_check_command_pre(sc, cm); 3097263363Semaste if (error) { 3098263363Semaste mtx_unlock(&sc->mfi_io_lock); 3099263363Semaste goto out; 3100263363Semaste } 3101263363Semaste } 3102263363Semaste if ((error = mfi_wait_command(sc, cm)) != 0) { 3103263363Semaste device_printf(sc->mfi_dev, 3104263363Semaste "Controller polled failed\n"); 3105263363Semaste mtx_unlock(&sc->mfi_io_lock); 3106263363Semaste goto out; 3107263363Semaste } 3108263363Semaste if (!skip_pre_post) { 3109263363Semaste mfi_check_command_post(sc, cm); 3110263363Semaste } 3111263363Semaste mtx_unlock(&sc->mfi_io_lock); 3112263363Semaste 3113263363Semaste if (cm->cm_frame->header.cmd != MFI_CMD_STP) { 3114263363Semaste temp = data; 3115263363Semaste if ((cm->cm_flags & MFI_CMD_DATAIN) || 3116263363Semaste (cm->cm_frame->header.cmd == MFI_CMD_STP)) { 3117263363Semaste for (i = 0; i < ioc->mfi_sge_count; i++) { 3118263363Semaste#ifdef COMPAT_FREEBSD32 3119263363Semaste if (cmd == MFI_CMD) { 3120263363Semaste#endif 3121263363Semaste /* Native */ 3122263363Semaste addr = ioc->mfi_sgl[i].iov_base; 3123263363Semaste len = ioc->mfi_sgl[i].iov_len; 3124263363Semaste#ifdef COMPAT_FREEBSD32 3125263363Semaste } else { 3126263363Semaste /* 32bit on 64bit */ 3127263363Semaste ioc32 = (struct mfi_ioc_packet32 *)ioc; 3128263363Semaste addr = PTRIN(ioc32->mfi_sgl[i].iov_base); 3129263363Semaste len = ioc32->mfi_sgl[i].iov_len; 3130263363Semaste } 3131263363Semaste#endif 3132263363Semaste error = copyout(temp, addr, len); 3133263363Semaste if (error != 0) { 3134263363Semaste device_printf(sc->mfi_dev, 3135263363Semaste "Copy out failed\n"); 3136263363Semaste goto out; 3137263363Semaste } 3138263363Semaste temp = &temp[len]; 3139263363Semaste } 3140263363Semaste } 3141263363Semaste } 3142263363Semaste 3143263363Semaste if (ioc->mfi_sense_len) { 3144263363Semaste /* get user-space sense ptr then copy out sense */ 3145263363Semaste bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off], 3146263363Semaste &sense_ptr.sense_ptr_data[0], 3147263363Semaste sizeof(sense_ptr.sense_ptr_data)); 3148263363Semaste#ifdef COMPAT_FREEBSD32 3149263363Semaste if (cmd != MFI_CMD) { 3150263363Semaste /* 3151263363Semaste * not 64bit native so zero out any address 3152263363Semaste * over 32bit */ 3153263363Semaste sense_ptr.addr.high = 0; 3154263363Semaste } 3155263363Semaste#endif 3156263363Semaste error = copyout(cm->cm_sense, sense_ptr.user_space, 3157263363Semaste ioc->mfi_sense_len); 3158263363Semaste if (error != 0) { 3159263363Semaste device_printf(sc->mfi_dev, 3160263363Semaste "Copy out failed\n"); 3161269024Semaste goto out; 3162269024Semaste } 3163269024Semaste } 3164263363Semaste 3165269024Semaste ioc->mfi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status; 3166263363Semasteout: 3167263363Semaste mfi_config_unlock(sc, locked); 3168263363Semaste if (data) 3169263363Semaste free(data, M_MFIBUF); 3170263363Semaste if (cm->cm_frame->header.cmd == MFI_CMD_STP) { 3171263363Semaste for (i = 0; i < 2; i++) { 3172263363Semaste if (sc->kbuff_arr[i]) { 3173263363Semaste if (sc->mfi_kbuff_arr_busaddr != 0) 3174263363Semaste bus_dmamap_unload( 3175263363Semaste sc->mfi_kbuff_arr_dmat[i], 3176263363Semaste sc->mfi_kbuff_arr_dmamap[i] 3177263363Semaste ); 3178263363Semaste if (sc->kbuff_arr[i] != NULL) 3179263363Semaste bus_dmamem_free( 3180263363Semaste sc->mfi_kbuff_arr_dmat[i], 3181263363Semaste sc->kbuff_arr[i], 3182263363Semaste sc->mfi_kbuff_arr_dmamap[i] 3183269024Semaste ); 3184269024Semaste if (sc->mfi_kbuff_arr_dmat[i] != NULL) 3185263363Semaste bus_dma_tag_destroy( 3186263363Semaste sc->mfi_kbuff_arr_dmat[i]); 3187263363Semaste } 3188263363Semaste } 3189263363Semaste } 3190263363Semaste if (cm) { 3191263363Semaste mtx_lock(&sc->mfi_io_lock); 3192263363Semaste mfi_release_command(cm); 3193263363Semaste mtx_unlock(&sc->mfi_io_lock); 3194263363Semaste } 3195263363Semaste 3196263363Semaste break; 3197263363Semaste } 3198263363Semaste case MFI_SET_AEN: 3199263363Semaste aen = (struct mfi_ioc_aen *)arg; 3200263363Semaste error = mfi_aen_register(sc, aen->aen_seq_num, 3201263363Semaste aen->aen_class_locale); 3202263363Semaste 3203269024Semaste break; 3204269024Semaste case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */ 3205263363Semaste { 3206263363Semaste devclass_t devclass; 3207263363Semaste struct mfi_linux_ioc_packet l_ioc; 3208263363Semaste int adapter; 3209263363Semaste 3210263363Semaste devclass = devclass_find("mfi"); 3211263363Semaste if (devclass == NULL) 3212263363Semaste return (ENOENT); 3213263363Semaste 3214263363Semaste error = copyin(arg, &l_ioc, sizeof(l_ioc)); 3215263363Semaste if (error) 3216263363Semaste return (error); 3217263363Semaste adapter = l_ioc.lioc_adapter_no; 3218263363Semaste sc = devclass_get_softc(devclass, adapter); 3219269024Semaste if (sc == NULL) 3220269024Semaste return (ENOENT); 3221263363Semaste return (mfi_linux_ioctl_int(sc->mfi_cdev, 3222263363Semaste cmd, arg, flag, td)); 3223263363Semaste break; 3224263363Semaste } 3225263363Semaste case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */ 3226263363Semaste { 3227263363Semaste devclass_t devclass; 3228263363Semaste struct mfi_linux_ioc_aen l_aen; 3229263363Semaste int adapter; 3230263363Semaste 3231263363Semaste devclass = devclass_find("mfi"); 3232263363Semaste if (devclass == NULL) 3233263363Semaste return (ENOENT); 3234269024Semaste 3235269024Semaste error = copyin(arg, &l_aen, sizeof(l_aen)); 3236263363Semaste if (error) 3237263363Semaste return (error); 3238263363Semaste adapter = l_aen.laen_adapter_no; 3239263363Semaste sc = devclass_get_softc(devclass, adapter); 3240263363Semaste if (sc == NULL) 3241263363Semaste return (ENOENT); 3242263363Semaste return (mfi_linux_ioctl_int(sc->mfi_cdev, 3243263363Semaste cmd, arg, flag, td)); 3244263363Semaste break; 3245263363Semaste } 3246263363Semaste#ifdef COMPAT_FREEBSD32 3247263363Semaste case MFIIO_PASSTHRU32: 3248263363Semaste if (!SV_CURPROC_FLAG(SV_ILP32)) { 3249263363Semaste error = ENOTTY; 3250263363Semaste break; 3251263363Semaste } 3252269024Semaste iop_swab.ioc_frame = iop32->ioc_frame; 3253269024Semaste iop_swab.buf_size = iop32->buf_size; 3254263363Semaste iop_swab.buf = PTRIN(iop32->buf); 3255263363Semaste iop = &iop_swab; 3256263363Semaste /* FALLTHROUGH */ 3257263363Semaste#endif 3258263363Semaste case MFIIO_PASSTHRU: 3259263363Semaste error = mfi_user_command(sc, iop); 3260263363Semaste#ifdef COMPAT_FREEBSD32 3261263363Semaste if (cmd == MFIIO_PASSTHRU32) 3262263363Semaste iop32->ioc_frame = iop_swab.ioc_frame; 3263263363Semaste#endif 3264263363Semaste break; 3265263363Semaste default: 3266263363Semaste device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); 3267263363Semaste error = ENOTTY; 3268263363Semaste break; 3269263363Semaste } 3270263363Semaste 3271263363Semaste return (error); 3272263363Semaste} 3273263363Semaste 3274263363Semastestatic int 3275263363Semastemfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 3276263363Semaste{ 3277263363Semaste struct mfi_softc *sc; 3278263363Semaste struct mfi_linux_ioc_packet l_ioc; 3279263363Semaste struct mfi_linux_ioc_aen l_aen; 3280263363Semaste struct mfi_command *cm = NULL; 3281263363Semaste struct mfi_aen *mfi_aen_entry; 3282263363Semaste union mfi_sense_ptr sense_ptr; 3283263363Semaste uint32_t context = 0; 3284263363Semaste uint8_t *data = NULL, *temp; 3285263363Semaste int i; 3286263363Semaste int error, locked; 3287263363Semaste 3288263363Semaste sc = dev->si_drv1; 3289263363Semaste error = 0; 3290263363Semaste switch (cmd) { 3291263363Semaste case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */ 3292263363Semaste error = copyin(arg, &l_ioc, sizeof(l_ioc)); 3293263363Semaste if (error != 0) 3294263363Semaste return (error); 3295263363Semaste 3296263363Semaste if (l_ioc.lioc_sge_count > MAX_LINUX_IOCTL_SGE) { 3297263363Semaste return (EINVAL); 3298263363Semaste } 3299263363Semaste 3300263363Semaste mtx_lock(&sc->mfi_io_lock); 3301263363Semaste if ((cm = mfi_dequeue_free(sc)) == NULL) { 3302263363Semaste mtx_unlock(&sc->mfi_io_lock); 3303263363Semaste return (EBUSY); 3304263363Semaste } 3305263363Semaste mtx_unlock(&sc->mfi_io_lock); 3306263363Semaste locked = 0; 3307263363Semaste 3308263363Semaste /* 3309263363Semaste * save off original context since copying from user 3310263363Semaste * will clobber some data 3311263363Semaste */ 3312263363Semaste context = cm->cm_frame->header.context; 3313263363Semaste 3314263363Semaste bcopy(l_ioc.lioc_frame.raw, cm->cm_frame, 3315263363Semaste 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */ 3316263363Semaste cm->cm_total_frame_size = (sizeof(union mfi_sgl) 3317263363Semaste * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off; 3318263363Semaste cm->cm_frame->header.scsi_status = 0; 3319263363Semaste cm->cm_frame->header.pad0 = 0; 3320263363Semaste if (l_ioc.lioc_sge_count) 3321263363Semaste cm->cm_sg = 3322263363Semaste (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off]; 3323263363Semaste cm->cm_flags = 0; 3324263363Semaste if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN) 3325263363Semaste cm->cm_flags |= MFI_CMD_DATAIN; 3326263363Semaste if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT) 3327263363Semaste cm->cm_flags |= MFI_CMD_DATAOUT; 3328263363Semaste cm->cm_len = cm->cm_frame->header.data_len; 3329263363Semaste if (cm->cm_len && 3330263363Semaste (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) { 3331263363Semaste cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF, 3332263363Semaste M_WAITOK | M_ZERO); 3333263363Semaste if (cm->cm_data == NULL) { 3334263363Semaste device_printf(sc->mfi_dev, "Malloc failed\n"); 3335263363Semaste goto out; 3336263363Semaste } 3337263363Semaste } else { 3338263363Semaste cm->cm_data = 0; 3339263363Semaste } 3340263363Semaste 3341263363Semaste /* restore header context */ 3342263363Semaste cm->cm_frame->header.context = context; 3343263363Semaste 3344263363Semaste temp = data; 3345263363Semaste if (cm->cm_flags & MFI_CMD_DATAOUT) { 3346263363Semaste for (i = 0; i < l_ioc.lioc_sge_count; i++) { 3347263363Semaste error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base), 3348263363Semaste temp, 3349263363Semaste l_ioc.lioc_sgl[i].iov_len); 3350263363Semaste if (error != 0) { 3351263363Semaste device_printf(sc->mfi_dev, 3352263363Semaste "Copy in failed\n"); 3353263363Semaste goto out; 3354263363Semaste } 3355263363Semaste temp = &temp[l_ioc.lioc_sgl[i].iov_len]; 3356263363Semaste } 3357263363Semaste } 3358263363Semaste 3359263363Semaste if (cm->cm_frame->header.cmd == MFI_CMD_DCMD) 3360263363Semaste locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode); 3361263363Semaste 3362263363Semaste if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) { 3363263363Semaste cm->cm_frame->pass.sense_addr_lo = 3364263363Semaste (uint32_t)cm->cm_sense_busaddr; 3365263363Semaste cm->cm_frame->pass.sense_addr_hi = 3366263363Semaste (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32); 3367263363Semaste } 3368263363Semaste 3369263363Semaste mtx_lock(&sc->mfi_io_lock); 3370263363Semaste error = mfi_check_command_pre(sc, cm); 3371263363Semaste if (error) { 3372263363Semaste mtx_unlock(&sc->mfi_io_lock); 3373263363Semaste goto out; 3374263363Semaste } 3375263363Semaste 3376263363Semaste if ((error = mfi_wait_command(sc, cm)) != 0) { 3377263363Semaste device_printf(sc->mfi_dev, 3378263363Semaste "Controller polled failed\n"); 3379263363Semaste mtx_unlock(&sc->mfi_io_lock); 3380263363Semaste goto out; 3381263363Semaste } 3382263363Semaste 3383263363Semaste mfi_check_command_post(sc, cm); 3384263363Semaste mtx_unlock(&sc->mfi_io_lock); 3385263363Semaste 3386263363Semaste temp = data; 3387263363Semaste if (cm->cm_flags & MFI_CMD_DATAIN) { 3388263363Semaste for (i = 0; i < l_ioc.lioc_sge_count; i++) { 3389263363Semaste error = copyout(temp, 3390263363Semaste PTRIN(l_ioc.lioc_sgl[i].iov_base), 3391263363Semaste l_ioc.lioc_sgl[i].iov_len); 3392263363Semaste if (error != 0) { 3393263363Semaste device_printf(sc->mfi_dev, 3394263363Semaste "Copy out failed\n"); 3395263363Semaste goto out; 3396263363Semaste } 3397263363Semaste temp = &temp[l_ioc.lioc_sgl[i].iov_len]; 3398263363Semaste } 3399263363Semaste } 3400263363Semaste 3401263363Semaste if (l_ioc.lioc_sense_len) { 3402263363Semaste /* get user-space sense ptr then copy out sense */ 3403263363Semaste bcopy(&((struct mfi_linux_ioc_packet*)arg) 3404269024Semaste ->lioc_frame.raw[l_ioc.lioc_sense_off], 3405269024Semaste &sense_ptr.sense_ptr_data[0], 3406263363Semaste sizeof(sense_ptr.sense_ptr_data)); 3407263363Semaste#ifdef __amd64__ 3408263363Semaste /* 3409263363Semaste * only 32bit Linux support so zero out any 3410263363Semaste * address over 32bit 3411263363Semaste */ 3412263363Semaste sense_ptr.addr.high = 0; 3413263363Semaste#endif 3414263363Semaste error = copyout(cm->cm_sense, sense_ptr.user_space, 3415263363Semaste l_ioc.lioc_sense_len); 3416263363Semaste if (error != 0) { 3417263363Semaste device_printf(sc->mfi_dev, 3418263363Semaste "Copy out failed\n"); 3419263363Semaste goto out; 3420263363Semaste } 3421263363Semaste } 3422263363Semaste 3423263363Semaste error = copyout(&cm->cm_frame->header.cmd_status, 3424263363Semaste &((struct mfi_linux_ioc_packet*)arg) 3425269024Semaste ->lioc_frame.hdr.cmd_status, 3426269024Semaste 1); 3427263363Semaste if (error != 0) { 3428263363Semaste device_printf(sc->mfi_dev, 3429263363Semaste "Copy out failed\n"); 3430263363Semaste goto out; 3431263363Semaste } 3432263363Semaste 3433263363Semasteout: 3434263363Semaste mfi_config_unlock(sc, locked); 3435263363Semaste if (data) 3436263363Semaste free(data, M_MFIBUF); 3437263363Semaste if (cm) { 3438263363Semaste mtx_lock(&sc->mfi_io_lock); 3439263363Semaste mfi_release_command(cm); 3440263363Semaste mtx_unlock(&sc->mfi_io_lock); 3441263363Semaste } 3442263363Semaste 3443263363Semaste return (error); 3444263363Semaste case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */ 3445263363Semaste error = copyin(arg, &l_aen, sizeof(l_aen)); 3446263363Semaste if (error != 0) 3447263363Semaste return (error); 3448263363Semaste printf("AEN IMPLEMENTED for pid %d\n", curproc->p_pid); 3449263363Semaste mfi_aen_entry = malloc(sizeof(struct mfi_aen), M_MFIBUF, 3450263363Semaste M_WAITOK); 3451263363Semaste mtx_lock(&sc->mfi_io_lock); 3452263363Semaste if (mfi_aen_entry != NULL) { 3453263363Semaste mfi_aen_entry->p = curproc; 3454263363Semaste TAILQ_INSERT_TAIL(&sc->mfi_aen_pids, mfi_aen_entry, 3455263363Semaste aen_link); 3456263363Semaste } 3457263363Semaste error = mfi_aen_register(sc, l_aen.laen_seq_num, 3458263363Semaste l_aen.laen_class_locale); 3459263363Semaste 3460263363Semaste if (error != 0) { 3461263363Semaste TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry, 3462263363Semaste aen_link); 3463263363Semaste free(mfi_aen_entry, M_MFIBUF); 3464263363Semaste } 3465263363Semaste mtx_unlock(&sc->mfi_io_lock); 3466263363Semaste 3467263363Semaste return (error); 3468263363Semaste default: 3469263363Semaste device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); 3470263363Semaste error = ENOENT; 3471263363Semaste break; 3472263363Semaste } 3473263363Semaste 3474263363Semaste return (error); 3475263363Semaste} 3476263363Semaste 3477263363Semastestatic int 3478263363Semastemfi_poll(struct cdev *dev, int poll_events, struct thread *td) 3479263363Semaste{ 3480263363Semaste struct mfi_softc *sc; 3481263363Semaste int revents = 0; 3482263363Semaste 3483263363Semaste sc = dev->si_drv1; 3484263363Semaste 3485263363Semaste if (poll_events & (POLLIN | POLLRDNORM)) { 3486263363Semaste if (sc->mfi_aen_triggered != 0) { 3487263363Semaste revents |= poll_events & (POLLIN | POLLRDNORM); 3488263363Semaste sc->mfi_aen_triggered = 0; 3489263363Semaste } 3490263363Semaste if (sc->mfi_aen_triggered == 0 && sc->mfi_aen_cm == NULL) { 3491263363Semaste revents |= POLLERR; 3492263363Semaste } 3493263363Semaste } 3494263363Semaste 3495263363Semaste if (revents == 0) { 3496263363Semaste if (poll_events & (POLLIN | POLLRDNORM)) { 3497269024Semaste sc->mfi_poll_waiting = 1; 3498269024Semaste selrecord(td, &sc->mfi_select); 3499263363Semaste } 3500263363Semaste } 3501263363Semaste 3502263363Semaste return revents; 3503263363Semaste} 3504263363Semaste 3505263363Semastestatic void 3506263363Semastemfi_dump_all(void) 3507263363Semaste{ 3508263363Semaste struct mfi_softc *sc; 3509263363Semaste struct mfi_command *cm; 3510263363Semaste devclass_t dc; 3511263363Semaste time_t deadline; 3512263363Semaste int timedout; 3513263363Semaste int i; 3514263363Semaste 3515263363Semaste dc = devclass_find("mfi"); 3516263363Semaste if (dc == NULL) { 3517263363Semaste printf("No mfi dev class\n"); 3518263363Semaste return; 3519263363Semaste } 3520263363Semaste 3521263363Semaste for (i = 0; ; i++) { 3522263363Semaste sc = devclass_get_softc(dc, i); 3523263363Semaste if (sc == NULL) 3524263363Semaste break; 3525263363Semaste device_printf(sc->mfi_dev, "Dumping\n\n"); 3526263363Semaste timedout = 0; 3527263363Semaste deadline = time_uptime - MFI_CMD_TIMEOUT; 3528263363Semaste mtx_lock(&sc->mfi_io_lock); 3529263363Semaste TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) { 3530263363Semaste if (cm->cm_timestamp < deadline) { 3531263363Semaste device_printf(sc->mfi_dev, 3532263363Semaste "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 3533263363Semaste cm, (int)(time_uptime - cm->cm_timestamp)); 3534263363Semaste MFI_PRINT_CMD(cm); 3535263363Semaste timedout++; 3536263363Semaste } 3537263363Semaste } 3538263363Semaste 3539263363Semaste#if 0 3540263363Semaste if (timedout) 3541263363Semaste MFI_DUMP_CMDS(SC); 3542263363Semaste#endif 3543263363Semaste 3544263363Semaste mtx_unlock(&sc->mfi_io_lock); 3545263363Semaste } 3546263363Semaste 3547263363Semaste return; 3548263363Semaste} 3549263363Semaste 3550263363Semastestatic void 3551263363Semastemfi_timeout(void *data) 3552263363Semaste{ 3553263363Semaste struct mfi_softc *sc = (struct mfi_softc *)data; 3554263363Semaste struct mfi_command *cm; 3555263363Semaste time_t deadline; 3556263363Semaste int timedout = 0; 3557263363Semaste 3558263363Semaste deadline = time_uptime - MFI_CMD_TIMEOUT; 3559263363Semaste if (sc->adpreset == 0) { 3560263363Semaste if (!mfi_tbolt_reset(sc)) { 3561263363Semaste callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, mfi_timeout, sc); 3562263363Semaste return; 3563263363Semaste } 3564263363Semaste } 3565263363Semaste mtx_lock(&sc->mfi_io_lock); 3566263363Semaste TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) { 3567263363Semaste if (sc->mfi_aen_cm == cm || sc->mfi_map_sync_cm == cm) 3568263363Semaste continue; 3569263363Semaste if (cm->cm_timestamp < deadline) { 3570269024Semaste if (sc->adpreset != 0 && sc->issuepend_done == 0) { 3571269024Semaste cm->cm_timestamp = time_uptime; 3572263363Semaste } else { 3573263363Semaste device_printf(sc->mfi_dev, 3574263363Semaste "COMMAND %p TIMEOUT AFTER %d SECONDS\n", 3575263363Semaste cm, (int)(time_uptime - cm->cm_timestamp) 3576263363Semaste ); 3577263363Semaste MFI_PRINT_CMD(cm); 3578263363Semaste MFI_VALIDATE_CMD(sc, cm); 3579263363Semaste timedout++; 3580263363Semaste } 3581263363Semaste } 3582263363Semaste } 3583263363Semaste 3584263363Semaste#if 0 3585263363Semaste if (timedout) 3586263363Semaste MFI_DUMP_CMDS(SC); 3587263363Semaste#endif 3588263363Semaste 3589263363Semaste mtx_unlock(&sc->mfi_io_lock); 3590263363Semaste 3591263363Semaste callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, 3592263363Semaste mfi_timeout, sc); 3593263363Semaste 3594263363Semaste if (0) 3595263363Semaste mfi_dump_all(); 3596263363Semaste return; 3597263363Semaste} 3598263363Semaste